Need Widget Help w/XML files

Topics: ASP.NET 2.0
Feb 9, 2009 at 11:41 PM
Hi all,

First let me say that I'm not a programmer, but I do understand some of the concepts.  I've created a new widget based on the newsletter widget that will allow someone to enter their name and email in the widget and click on submit.  When they click submit I have the widget then creating an email with an attachment, and sending it to the email address that was entered in the widget.

I'm wondering if someone would help me by showing me how to take the new field "name" in the widget and add it to the xml file that is stored on the server which currently only stores the email address.  Secondly, since the edit.ascx also allows the viewing and deletion of those emails, I would need to understand how to modify that code to make sure that both get deleted properly.  Lastly, I would then like to use their name in the email that I send. 

I have attached the four files that I'm using for this widget.  Any help would be greatly appreciated.  If you are really ambitious, I'm also planning on having the attachment's file name and its location being two fields in the edit script so that I don't have to hard code the reference to them in the code.  I have not done that as I have no idea of how to accomplish it.  But, beggers can't be choosey, so if anyone can help me with just the xml file that would be terrific!

btw, when this is done and if someone would like to post it, if it's deserving of posting, that would be fine by me.  Keep in mind that I'm not a programmer, more of a hack!, so please be kind. :)

Thanks,
Brian

widget.ascx --------------------------------------------

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="widget.ascx.cs" Inherits="widgets_FreeReport_widget" %>

<style type="text/css">
    .style1
    {
        font-size: medium;
    }
</style>

<div id="freereportform">
  <p class="style1">For you FREE report please fill in the following:</p>
 
  <label for="<%=txtName.ClientID %>">Name:</label>
  <asp:TextBox runat="server" ID="txtName" Width="95%" />

  <label for="<%=txtEmail.ClientID %>">Email:</label>
  <asp:TextBox runat="server" ID="txtEmail" Width="95%" />
 
   <asp:RequiredFieldValidator
    runat="server"
    ControlToValidate="txtName"
    ErrorMessage="Please enter your name"
    Display="dynamic"
    ValidationGroup="freereport" />
 
  <asp:RequiredFieldValidator
    runat="server"
    ControlToValidate="txtEmail"
    ErrorMessage="Please enter an e-mail address"
    Display="dynamic"
    ValidationGroup="freereport" />
   
  <asp:RegularExpressionValidator
    runat="server"
    ControlToValidate="txtEmail"
    ErrorMessage="<%$Resources:labels, enterValidEmail %>"
    ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"
    Display="dynamic"
    ValidationGroup="freereport" />
   
    <br />

  <div style="text-align:center">
    <asp:Button runat="server" ID="btnSave" ValidationGroup="freereport" Text="Submit" OnClientClick="return beginAddEmail()" />
  </div>
</div>

<div id="freereportthanks" style="display:none;text-align:center">
  <br /><br />
  <h2 id="freereportaction">Thank you</h2>
  <br /><br />
</div>

<script type="text/javascript">
  function beginAddEmail()
  {
    if(!Page_ClientValidate())
      return false;
     
    var arg = $('<%=txtEmail.ClientID %>').value;
    var context = 'freereport';
    <%=Page.ClientScript.GetCallbackEventReference(this, "arg", "endAddEmail", "context") %>;
   
    return false;
  }
 
  function endAddEmail(arg, context)
  {
    $('freereportform').style.display = 'none';
    $('freereportthanks').style.display = 'block';
    if (arg == "false")
    {
      $('freereportaction').innerHTML = "You are now unsubscribed";
    }
  }
</script>


widget.ascx.cs -----------------------------------------

#region using

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Xml;
using BlogEngine.Core;
using System.Net.Mail;

#endregion

public partial class widgets_FreeReport_widget : WidgetBase, ICallbackEventHandler
{

    public override string Name
    {
        get { return "FREE REPORT"; }
    }

    public override bool IsEditable
    {
        get { return true; }
    }

    public override void LoadWidget()
    {

    }

    #region Event handling

    protected void Page_Load(object sender, EventArgs e)
    {
        UserControl userControl = (UserControl)sender;
        if (userControl != null)
        {
            if (userControl.Request.QueryString["RemoveEmail"] != null)
            {
                string email = userControl.Request.QueryString["RemoveEmail"];
                AddEmail(email);
            }
        }
    }

    private static string _FileName2;

    private static MailMessage CreateEmail()
    {
        MailMessage mail = new MailMessage();
        mail.Subject = String.Format("Your free report from {0}<br /><br />", BlogSettings.Instance.Name);
        mail.Body = String.Format("You receive this e-mail because you requested our free report at {0}<br /><br />", BlogSettings.Instance.Name);
        mail.Body += "To be removed from our list, simply click on the link below and reenter your email. <br />";
        mail.Body += "You will then be removed from our list.";

        mail.Body += "<br /><a href=\"" + Utils.AbsoluteWebRoot + "\">" + Utils.AbsoluteWebRoot + "</a>";
        mail.From = new MailAddress(BlogSettings.Instance.Email, BlogSettings.Instance.Name);

        _FileName2 = Path.Combine(BlogSettings.Instance.StorageLocation, "FreeReport.pdf");
        _FileName2 = System.Web.Hosting.HostingEnvironment.MapPath(_FileName2);

        mail.Attachments.Add(new Attachment(_FileName2));
        return mail;
    }

    #endregion

    #region Save and retrieve e-mails

    private static XmlDocument _Doc;
    private static string _FileName;

    private void AddEmail(string email)
    {
        try
        {
            LoadEmails();

            if (!DoesEmailExist(email))
            {
                XmlNode node = _Doc.CreateElement("email");
                node.InnerText = email;
                _Doc.FirstChild.AppendChild(node);

                _Callback = "true";
                SaveEmails();
            }
            else
            {
                _Doc.FirstChild.RemoveChild(_Doc.SelectSingleNode("emails/email[text()='" + email + "']"));
                _Callback = "false";
                SaveEmails();
            }
// This section is where I'm getting the widget to send the email address entered on the form.
            MailMessage mail = CreateEmail();

            //mail.To.Add(node.InnerText.Trim());
            mail.CC.Add (BlogEngine.Core.BlogSettings.Instance.Email.ToString()); // For testing I'm also sending to email in settings.
            mail.To.Add(email);  // This is the email from the widget form

            Utils.SendMailMessageAsync(mail);
// End of the section where I'm sending the email...
        }
        catch
        {
            _Callback = "false";
        }
    }

    private bool DoesEmailExist(string email)
    {
        return _Doc.SelectSingleNode("emails/email[text()='" + email + "']") != null;
    }

    private static void LoadEmails()
    {
        if (_Doc == null || _FileName == null)
        {
            _FileName = Path.Combine(BlogSettings.Instance.StorageLocation, "freereport.xml");
            _FileName = System.Web.Hosting.HostingEnvironment.MapPath(_FileName);

            if (File.Exists(_FileName))
            {
                _Doc = new XmlDocument();
                _Doc.Load(_FileName);
            }
            else
            {
                _Doc = new XmlDocument();
                _Doc.LoadXml("<emails></emails>");
            }
        }
    }

    private void SaveEmails()
    {
        using (MemoryStream ms = new MemoryStream())
        using (FileStream fs = File.Open(_FileName, FileMode.Create, FileAccess.Write))
        {
            _Doc.Save(ms);
            ms.WriteTo(fs);
        }
    }

    #endregion

    #region ICallbackEventHandler Members

    private string _Callback;

    /// <summary>
    /// Returns the results of a callback event that targets a control.
    /// </summary>
    /// <returns>The result of the callback.</returns>
    public string GetCallbackResult()
    {
        return _Callback;
    }

    /// <summary>
    /// Processes a callback event that targets a control.
    /// </summary>
    /// <param name="eventArgument">A string that represents an event argument to pass to the event handler.</param>
    public void RaiseCallbackEvent(string eventArgument)
    {
        _Callback = eventArgument;
        AddEmail(eventArgument);
    }

    #endregion
}


edit.ascx -----------------------------------------------

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="edit.ascx.cs" Inherits="widgets_FreeReport_edit" %>
<asp:GridView
  runat="server"
  id="gridEmails"
  AlternatingRowStyle-BackColor="#F1F1F1"
  AutoGenerateColumns="False"
  AutoGenerateDeleteButton="true">
 
  <Columns>
    <asp:BoundField HeaderText="Email" DataField="innertext" />
  </Columns>
</asp:GridView>


edit.ascx.cs --------------------------------------------

using System;
using System.Web;
using System.IO;
using System.Xml;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using BlogEngine.Core;

public partial class widgets_FreeReport_edit : WidgetEditBase
{
 protected void Page_Load(object sender, EventArgs e)
 {
  if (!Page.IsPostBack)
  {
   _Doc = null;
   BindGrid();
  }

  gridEmails.RowDeleting += new GridViewDeleteEventHandler(gridEmails_RowDeleting);
  gridEmails.RowDataBound += new GridViewRowEventHandler(gridEmails_RowDataBound);
}

 private void BindGrid()
 {
  LoadEmails();
 
  gridEmails.DataKeyNames = new string[] { "innertext" };
  gridEmails.DataSource = _Doc.FirstChild;
  gridEmails.DataBind();
 }

 void gridEmails_RowDataBound(object sender, GridViewRowEventArgs e)
 {
  if (e.Row.RowType == DataControlRowType.DataRow && !Page.IsPostBack)
  {
   LinkButton delete = e.Row.Cells[0].Controls[0] as LinkButton;
   if (delete != null)
   {
    delete.OnClientClick = "return confirm('Are you sure you want to delete this e-mail?')";
   }
  }
 }

 void gridEmails_RowDeleting(object sender, GridViewDeleteEventArgs e)
 {
  LoadEmails();
  string email = (string)gridEmails.DataKeys[e.RowIndex].Value;
  XmlNode node = _Doc.SelectSingleNode("emails/email[text()='" + email + "']");
  if (node != null)
  {
   _Doc.FirstChild.RemoveChild(node);
   BindGrid();
  }
 }

 private static XmlDocument _Doc;
 private static string _FileName;

 private static void LoadEmails()
 {
  if (_Doc == null || _FileName == null)
  {
   _FileName = Path.Combine(BlogSettings.Instance.StorageLocation, "FreeReport.xml");
   _FileName = System.Web.Hosting.HostingEnvironment.MapPath(_FileName);

   if (File.Exists(_FileName))
   {
    _Doc = new XmlDocument();
    _Doc.Load(_FileName);
   }
   else
   {
    _Doc = new XmlDocument();
    _Doc.LoadXml("<emails></emails>");
   }
  }
 }

 private void SaveEmails()
 {
  using (MemoryStream ms = new MemoryStream())
  using (FileStream fs = File.Open(_FileName, FileMode.Create, FileAccess.Write))
  {
   _Doc.Save(ms);
   ms.WriteTo(fs);
  }
 }

 public override void Save()
 {
  SaveEmails();
 }
}

Coordinator
Feb 10, 2009 at 1:44 AM
Okay, I took a stab at it :)  Here's the files I've got.  You can put the name of the file you want to attach in the box when you click the Edit button (e.g. FreeReport.pdf).  I'd recommend clearing out your freereport.xml file since the format's a little different now.

====== edit.ascx ======

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="edit.ascx.cs" Inherits="widgets_FreeReport_edit" %>
Attachment file name: <asp:TextBox ID="txtAttachmentFileName" runat="server"></asp:TextBox>
<br /><br />
<asp:GridView
  runat="server"
  id="gridEmails"
  AlternatingRowStyle-BackColor="#F1F1F1"
  AutoGenerateColumns="False">
 
  <Columns>
    <asp:TemplateField HeaderText="">
        <ItemTemplate>
            <asp:LinkButton ID="lbDelete" runat="server" Text="Delete"></asp:LinkButton>
        </ItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField HeaderText="Name">
        <ItemTemplate>
            <asp:Literal ID="litName" runat="server"></asp:Literal>
        </ItemTemplate>
    </asp:TemplateField>
    <asp:TemplateField HeaderText="Email Address">
        <ItemTemplate>
            <asp:Literal ID="litEmail" runat="server"></asp:Literal>
        </ItemTemplate>
    </asp:TemplateField>
  </Columns>
</asp:GridView>



====== edit.ascx.cs ======

using System;
using System.Web;
using System.IO;
using System.Xml;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using BlogEngine.Core;

public partial class widgets_FreeReport_edit : WidgetEditBase
{
 protected void Page_Load(object sender, EventArgs e)
 {
     gridEmails.RowDataBound += new GridViewRowEventHandler(gridEmails_RowDataBound);
     gridEmails.RowCommand += new GridViewCommandEventHandler(gridEmails_RowCommand);

  if (!Page.IsPostBack)
  {
      _Doc = null;
   BindGrid();
   GetAttachmentFilename();
  }

}
 private static string _AttachmentFileName;
 private void GetAttachmentFilename()
 {
   _AttachmentFileName = Path.Combine(BlogSettings.Instance.StorageLocation, "FreeReportAttachmentFileName.txt");
   _AttachmentFileName = System.Web.Hosting.HostingEnvironment.MapPath(_AttachmentFileName);

   if (File.Exists(_AttachmentFileName))
   {
       txtAttachmentFileName.Text = File.ReadAllText(_AttachmentFileName);
   }

 }
 private void SaveAttachmentFilename()
 {
     File.WriteAllText(_AttachmentFileName, txtAttachmentFileName.Text.Trim());
 }
 private void BindGrid()
 {
  LoadEmails();  

  gridEmails.DataSource = _Doc.FirstChild;
  gridEmails.DataBind();
 }

 void gridEmails_RowDataBound(object sender, GridViewRowEventArgs e)
 {
  if (e.Row.RowType == DataControlRowType.DataRow)
  {
      Literal litName = (Literal)e.Row.FindControl("litName");
      Literal litEmail = (Literal)e.Row.FindControl("litEmail");
      XmlElement element = (XmlElement)e.Row.DataItem;

      litName.Text = element.SelectSingleNode("name").InnerText;
      litEmail.Text = element.SelectSingleNode("address").InnerText;

      LinkButton lbDelete = (LinkButton)e.Row.FindControl("lbDelete");
      lbDelete.OnClientClick = "return confirm('Are you sure you want to delete this e-mail?')";
      lbDelete.CommandArgument = litEmail.Text;

  }
 }

 void gridEmails_RowCommand(object sender, GridViewCommandEventArgs e)
 {
     string emailToDelete = (string)e.CommandArgument;
     if (string.IsNullOrEmpty(emailToDelete))
         return;

  LoadEmails();
 
  XmlNode node = _Doc.SelectSingleNode("emails/email/address[text()='" + emailToDelete + "']");
  if (node != null)
  {
   _Doc.FirstChild.RemoveChild(node.ParentNode);
   BindGrid();
  }
 }

 private static XmlDocument _Doc;
 private static string _FileName;

 private static void LoadEmails()
 {
  if (_Doc == null || _FileName == null)
  {
   _FileName = Path.Combine(BlogSettings.Instance.StorageLocation, "FreeReport.xml");
   _FileName = System.Web.Hosting.HostingEnvironment.MapPath(_FileName);

   if (File.Exists(_FileName))
   {
    _Doc = new XmlDocument();
    _Doc.Load(_FileName);
   }
   else
   {
    _Doc = new XmlDocument();
    _Doc.LoadXml("<emails></emails>");
   }
  }
 }

 private void SaveEmails()
 {
  using (MemoryStream ms = new MemoryStream())
  using (FileStream fs = File.Open(_FileName, FileMode.Create, FileAccess.Write))
  {
   _Doc.Save(ms);
   ms.WriteTo(fs);
  }
 }

 public override void Save()
 {
  SaveEmails();
  SaveAttachmentFilename();
 }
}



====== widget.ascx ======

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="widget.ascx.cs" Inherits="widgets_FreeReport_widget" %>

<style type="text/css">
    .style1
    {
        font-size: medium;
    }
</style>

<div id="freereportform">
  <p class="style1">For you FREE report please fill in the following:</p>
 
  <label for="<%=txtName.ClientID %>">Name:</label>
  <asp:TextBox runat="server" ID="txtName" Width="95%" />

  <label for="<%=txtEmail.ClientID %>">Email:</label>
  <asp:TextBox runat="server" ID="txtEmail" Width="95%" />
 
   <asp:RequiredFieldValidator
    runat="server"
    ControlToValidate="txtName"
    ErrorMessage="Please enter your name"
    Display="dynamic"
    ValidationGroup="freereport" />
 
  <asp:RequiredFieldValidator
    runat="server"
    ControlToValidate="txtEmail"
    ErrorMessage="Please enter an e-mail address"
    Display="dynamic"
    ValidationGroup="freereport" />
   
  <asp:RegularExpressionValidator
    runat="server"
    ControlToValidate="txtEmail"
    ErrorMessage="<%$Resources:labels, enterValidEmail %>"
    ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"
    Display="dynamic"
    ValidationGroup="freereport" />
   
    <br />

  <div style="text-align:center">
    <asp:Button runat="server" ID="btnSave" ValidationGroup="freereport" Text="Submit" OnClientClick="return beginAddEmail()" />
  </div>
</div>

<div id="freereportthanks" style="display:none;text-align:center">
  <br /><br />
  <h2 id="freereportaction">Thank you</h2>
  <br /><br />
</div>

<script type="text/javascript">
  function beginAddEmail()
  {
    if(!Page_ClientValidate())
      return false;
     
    var arg = $('<%=txtEmail.ClientID %>').value + '|' + $('<%=txtName.ClientID %>').value;
    var context = 'freereport';
    <%=Page.ClientScript.GetCallbackEventReference(this, "arg", "endAddEmail", "context") %>;
   
    return false;
  }
 
  function endAddEmail(arg, context)
  {
    $('freereportform').style.display = 'none';
    $('freereportthanks').style.display = 'block';
    if (arg == "false")
    {
      $('freereportaction').innerHTML = "You are now unsubscribed";
    }
  }
</script>



====== widget.ascx.cs ======

#region using

using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Xml;
using BlogEngine.Core;
using System.Net.Mail;

#endregion

public partial class widgets_FreeReport_widget : WidgetBase, ICallbackEventHandler
{

    public override string Name
    {
        get { return "FREE REPORT"; }
    }

    public override bool IsEditable
    {
        get { return true; }
    }

    public override void LoadWidget()
    {

    }

    #region Event handling

    protected void Page_Load(object sender, EventArgs e)
    {
        //UserControl userControl = (UserControl)sender;
        //if (userControl != null)
        //{
        //    if (userControl.Request.QueryString["RemoveEmail"] != null)
        //    {
        //        string email = userControl.Request.QueryString["RemoveEmail"];
        //        AddEmail(email);
        //    }
        //}
    }

    private static string _FileName2;

    private static MailMessage CreateEmail()
    {
        MailMessage mail = new MailMessage();
        mail.Subject = String.Format("Your free report from {0}<br /><br />", BlogSettings.Instance.Name);
        mail.Body = String.Format("You receive this e-mail because you requested our free report at {0}<br /><br />", BlogSettings.Instance.Name);
        mail.Body += "To be removed from our list, simply click on the link below and reenter your email. <br />";
        mail.Body += "You will then be removed from our list.";

        mail.Body += "<br /><a href=\"" + Utils.AbsoluteWebRoot + "\">" + Utils.AbsoluteWebRoot + "</a>";
        mail.From = new MailAddress(BlogSettings.Instance.Email, BlogSettings.Instance.Name);

        if (string.IsNullOrEmpty(_FileName2))
        {
            string attachmentFileName = Path.Combine(BlogSettings.Instance.StorageLocation, "FreeReportAttachmentFileName.txt");
            attachmentFileName = System.Web.Hosting.HostingEnvironment.MapPath(attachmentFileName);

            if (File.Exists(attachmentFileName))
            {
                string fileName = File.ReadAllText(attachmentFileName);
                if (!string.IsNullOrEmpty(fileName))
                {
                    _FileName2 = Path.Combine(BlogSettings.Instance.StorageLocation, fileName);
                    _FileName2 = System.Web.Hosting.HostingEnvironment.MapPath(_FileName2);
                    if (!File.Exists(_FileName2))
                        _FileName2 = null;
                }
            }
        }

        if (!string.IsNullOrEmpty(_FileName2))
        {
            mail.Attachments.Add(new Attachment(_FileName2));
        }        

        return mail;
    }

    #endregion

    #region Save and retrieve e-mails

    private static XmlDocument _Doc;
    private static string _FileName;

    private void AddEmail(string email, string name)
    {
        try
        {
            LoadEmails();

            if (!DoesEmailExist(email))
            {
                XmlNode addressNode = _Doc.CreateElement("address");
                addressNode.InnerText = email;

                XmlNode nameNode = _Doc.CreateElement("name");
                nameNode.InnerText = name;

                XmlNode node = _Doc.CreateElement("email");
                node.AppendChild(addressNode);
                node.AppendChild(nameNode);

                _Doc.FirstChild.AppendChild(node);

                _Callback = "true";
                SaveEmails();

                // This section is where I'm getting the widget to send the email address entered on the form.
                MailMessage mail = CreateEmail();

                //mail.To.Add(node.InnerText.Trim());
                mail.CC.Add(BlogEngine.Core.BlogSettings.Instance.Email.ToString()); // For testing I'm also sending to email in settings.
                mail.To.Add(email);  // This is the email from the widget form

                Utils.SendMailMessageAsync(mail);
                // End of the section where I'm sending the email...

            }
            else
            {
                _Doc.FirstChild.RemoveChild(_Doc.SelectSingleNode("emails/email/address[text()='" + email + "']").ParentNode);
                _Callback = "false";
                SaveEmails();
            }
        }
        catch (Exception ex)
        {
            _Callback = "false";
        }
    }

    private bool DoesEmailExist(string email)
    {
        return _Doc.SelectSingleNode("emails/email/address[text()='" + email + "']") != null;
    }

    private static void LoadEmails()
    {
        if (_Doc == null || _FileName == null)
        {
            _FileName = Path.Combine(BlogSettings.Instance.StorageLocation, "freereport.xml");
            _FileName = System.Web.Hosting.HostingEnvironment.MapPath(_FileName);

            if (File.Exists(_FileName))
            {
                _Doc = new XmlDocument();
                _Doc.Load(_FileName);
            }
            else
            {
                _Doc = new XmlDocument();
                _Doc.LoadXml("<emails></emails>");
            }
        }
    }

    private void SaveEmails()
    {
        using (MemoryStream ms = new MemoryStream())
        using (FileStream fs = File.Open(_FileName, FileMode.Create, FileAccess.Write))
        {
            _Doc.Save(ms);
            ms.WriteTo(fs);
        }
    }

    #endregion

    #region ICallbackEventHandler Members

    private string _Callback;

    /// <summary>
    /// Returns the results of a callback event that targets a control.
    /// </summary>
    /// <returns>The result of the callback.</returns>
    public string GetCallbackResult()
    {
        return _Callback;
    }

    /// <summary>
    /// Processes a callback event that targets a control.
    /// </summary>
    /// <param name="eventArgument">A string that represents an event argument to pass to the event handler.</param>
    public void RaiseCallbackEvent(string eventArgument)
    {
        if (!string.IsNullOrEmpty(eventArgument) && eventArgument.Contains("|"))
        {
            //_Callback = eventArgument;

            string[] parts = eventArgument.Split('|');
            string email = parts[0].Trim();
            string name = parts[1].Trim();            
            AddEmail(email, name);
        }
    }

    #endregion
}

Feb 10, 2009 at 11:43 PM

Ben,

You are sooooo good!  Works like a champ.  I really appreciate all your help.

However, I do have a bone to pick with you.  Within 2 hours of me posting my message you managed to provide me with a workable solution, now my wife is asking me why it has taken me the past week to get what I had, working.  :)

Thanks again,
Brian