Showing posts with label XML. Show all posts
Showing posts with label XML. Show all posts

Sunday, July 21, 2013

How to create and read Xml in asp.net

We often have to deal with Xml message when our applications are integrated with SMS Api, Email Api or Payment Api. At that time, we prepare Xml message and feed the services. Likewise, it gets the Xml message from the service of API and extracts the message from Xml message for on-going process. This post explain step by step how to create Xml message and read the message from Xml elements.

First, copy and paste the following Xml message to new file "XmlMessage.xml" in "App_Data" folder in your project. You see "[xxxxxxx]" and it is place holder for data we put.
<?xml version="1.0" encoding="utf-8" ?>
<paymentService version="1.4" merchantCode="[merchantCode]">
  <reply>
    <orderStatus orderCode="[orderCode]">
      <payment>
        <paymentMethod>[paymentMethod]</paymentMethod>
        <amount value="[value]" currencyCode="[currencyCode]" exponent="[exponent]"/>
        <lastEvent>[lastEvent]</lastEvent>
        <CVCResultCode description="[CVCResultCode]"/>
        <ISO8583ReturnCode code="[ISO8583ReturnCode]" description="[ISO8583ReturnDescription]"/>
      </payment>
    </orderStatus>
  </reply>
</paymentService>
Second, we need to add Textbox server control to .aspx page as below:
<body>
    <form id="form1" runat="server">
    <div>
        <asp:TextBox ID="txtXml" runat="server" Height="250px" Width="576px" 
            TextMode="MultiLine"></asp:TextBox>
    </div>
    </form>
</body>
Third, copy and paste the following code in code behind.
protected void Page_Load(object sender, EventArgs e)
{
    //Set the data here.
    string merchantCode = "MYMERCHANT";
    string orderCode = "T0211234";
    string paymentMethod = "ECMC-SSL";
    string value = "162095";
    string currencyCode = "GPB";
    string exponent = "2";
    string lastEvent = "REFUSED";
    string CVCResultCode = "NOT SUPPLIED BY SHOPPER";
    string ISO8583ReturnCode = "33";
    string ISO8583ReturnDescription = "CARD EXPIRED";

    string xmlMsg = GetXmlMessage();
    //Fill the data in place holder in Xml message.
    xmlMsg = xmlMsg.Replace("[merchantCode]", merchantCode);
    xmlMsg = xmlMsg.Replace("[orderCode]", orderCode);
    xmlMsg = xmlMsg.Replace("[paymentMethod]", paymentMethod);
    xmlMsg = xmlMsg.Replace("[value]", value);
    xmlMsg = xmlMsg.Replace("[currencyCode]", currencyCode);
    xmlMsg = xmlMsg.Replace("[exponent]", exponent);
    xmlMsg = xmlMsg.Replace("[lastEvent]", lastEvent);
    xmlMsg = xmlMsg.Replace("[CVCResultCode]", CVCResultCode);
    xmlMsg = xmlMsg.Replace("[ISO8583ReturnCode]", ISO8583ReturnCode);
    xmlMsg = xmlMsg.Replace("[ISO8583ReturnDescription]", ISO8583ReturnDescription);
    txtXml.Text = xmlMsg;
    ReadXmlMessage(xmlMsg);
}

public string GetXmlMessage()
{
    //Get Xml message from file.
    string XmlFile = "~/App_Data/XmlMessage.xml";
    StreamReader sr = new StreamReader(Server.MapPath(XmlFile));
    string str = sr.ReadToEnd();
    return str;
}

public void ReadXmlMessage(string xmlMsg)
{
    if (!string.IsNullOrEmpty(xmlMsg))
    {
        //Read the data from Xml elements.
        XmlDocument document = new XmlDocument();
        document.LoadXml(xmlMsg);
        string merchantCode = document.GetElementsByTagName("paymentService")[0].Attributes["merchantCode"].Value;
        string orderCode = document.GetElementsByTagName("orderStatus")[0].Attributes["orderCode"].Value;
        string paymentMethod = document.SelectSingleNode("//paymentMethod").InnerText;
        string value = document.GetElementsByTagName("amount")[0].Attributes["value"].Value;
        string currencyCode = document.GetElementsByTagName("amount")[0].Attributes["currencyCode"].Value;
        string exponent = document.GetElementsByTagName("amount")[0].Attributes["exponent"].Value;
        string lastEvent = document.SelectSingleNode("//lastEvent").InnerText;
        string CVCResultCode = document.GetElementsByTagName("CVCResultCode")[0].Attributes["description"].Value;
        string ISO8583ReturnCode = document.SelectSingleNode("//ISO8583ReturnCode").Attributes["code"].Value;
        string ISO8583ReturnDescription = document.SelectSingleNode("//ISO8583ReturnCode").Attributes["description"].Value;
    }
}
I use XmlNode.SelectSingleNode method to get xml data. It selects the first XmlNode that matches the XPath expression. The first XmlNode that matches the XPath query or null if no matching node is found.
I used aslo XmlDocument.GetElementsByTagName method to return an XmlNodeList containing a list of all descendant elements that match the specified Name. If no nodes match name, the returned collection will be empty.

Finally, run and see the result. It look like as below:

Sunday, September 30, 2012

How to save web site configuration data in Xml file instead of web.config.

We often use web.config file to keep the site configuration data. In this case, there is draw back since it need to restart the application when we change web.config file everytimes, and it don't affect the current running transaction. There is a simple way to solve it out that is XML file to save web site configuration data when we don't want to use Database for that. Perhaps we should consider what would happen if we use XML file for sensitive data concerned with security risk. Anyway, let's start here.
First, create xml file "site-config.xml" in "App_Data" folder as below:
<?xml version="1.0"?>
<SiteSettings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <SiteName>Aspmemo.net</SiteName>
  <SiteVersion>1.0</SiteVersion>
  <SiteEmailAddress>sithuwin@aspmemo.net</SiteEmailAddress>
</SiteSettings>
Second, create "SiteSettings.cs" as follows:
using System.IO;
using System.Text;
using System.Xml.Serialization;

public class SiteSettings
{
    private const string XmlConfigFile = "~/App_Data/site-config.xml";
    private string _siteName;
    private string _siteVersion;
    private string _siteEmail;

    public string SiteName
    {
        get
        {
            return _siteName;
        }
        set
        {
            lock (this)
            {
                _siteName = value;
            }
        }
    }
    public string SiteVersion
    {
        get
        {
            return _siteVersion;
        }
        set
        {
            lock (this)
            {
                _siteVersion = value;
            }
        }
    }
    public string SiteEmailAddress
    {
        get
        {
            return _siteEmail;
        }
        set
        {
            lock (this)
            {
                _siteEmail = value;
            }
        }
    }
    public string SiteEmailFromField
    {
        get
        {
            return String.Format("{0} <{1}>", _siteName, _siteEmail);
        }
    }
    public static SiteSettings LoadFromConfiguration()
    {
        SiteSettings s = LoadFromXml();

        if (s == null)
        {
            s = new SiteSettings();
            //s.StorePhotosInDatabase = false;
            //s.ServerPhotoUploadDirectory = "Upload";
            s.SiteName = "Aspmemo";
            s.SiteVersion = "1.0";
            s.SiteEmailAddress = "sithuwin@aspmemo.net";
            SaveToXml(s);

        }
        return s;
    }
    public static SiteSettings GetSharedSettings()
    {
        return SiteHttpApplication.SiteApplicationSettings;
    }
    public static bool UpdateSettings(SiteSettings newSettings)
    {
        // write settings to code or db
        // update Application-wide settings, only over-writing settings that users should edit
        lock (SiteHttpApplication.SiteApplicationSettings)
        {
            // Site Name
            SiteHttpApplication.SiteApplicationSettings.SiteName = newSettings.SiteName;
            // Site Version
            SiteHttpApplication.SiteApplicationSettings.SiteVersion = newSettings.SiteVersion;
            // Contact Email Address for Site
            SiteHttpApplication.SiteApplicationSettings.SiteEmailAddress = newSettings.SiteEmailAddress;
            // Serialize to Xml Config File
            return SaveToXml(SiteHttpApplication.SiteApplicationSettings);
        }
    }
    private static SiteSettings LoadFromXml()
    {
        SiteSettings settings = null;
        HttpContext context = HttpContext.Current;
        if (context != null)
        {
            string configPath = context.Server.MapPath(XmlConfigFile);
            XmlSerializer xml = null;
            FileStream fs = null;
            bool success = false;
            int numAttempts = 0;

            while (!success && numAttempts < 2)
            {
                try
                {
                    numAttempts++;
                    xml = new XmlSerializer(typeof(SiteSettings));
                    fs = new FileStream(configPath, System.IO.FileMode.Open, System.IO.FileAccess.Read);
                    settings = xml.Deserialize(fs) as SiteSettings;
                    success = true;
                }
                catch (Exception x)
                {
                    // if an exception is thrown, there might have been a sharing violation;
                    // we wait and try again (max: two attempts)
                    success = false;
                    System.Threading.Thread.Sleep(1000);
                    if (numAttempts == 2)
                        throw new Exception("The Site Configuration could not be loaded.", x);
                }
            }
            if (fs != null)
                fs.Close();
        }
        return settings;
    }
    public string GetXml()
    {
        StringBuilder result = new StringBuilder();
        StringWriter s = new StringWriter(result);
        try
        {
            XmlSerializer xml = new XmlSerializer(typeof(SiteSettings));
            xml.Serialize(s, this);
        }
        finally
        {
            s.Close();
        }
        return result.ToString();
    }
    private static bool SaveToXml(SiteSettings settings)
    {
        if (settings == null)
            return false;
        HttpContext context = HttpContext.Current;
        if (context == null)
            return false;

        string configPath = context.Server.MapPath(XmlConfigFile);
        XmlSerializer xml = null;
        System.IO.FileStream fs = null;
        bool success = false;
        int numAttempts = 0;

        while (!success && numAttempts < 2)
        {
            try
            {
                numAttempts++;
                xml = new XmlSerializer(typeof(SiteSettings));
                fs = new FileStream(configPath, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
                xml.Serialize(fs, settings);
                success = true;
            }
            catch
            {
                // if an exception is thrown, there might have been a sharing violation;
                // we wait and try again (max: two attempts)
                success = false;
                System.Threading.Thread.Sleep(1000);
            }
        }
        if (fs != null)
            fs.Close();
        return success;
    }
}
Third, create "SiteHttpApplication.cs" as the custom base class for applications:
public class SiteHttpApplication : HttpApplication
{
 private static object _settingsLock = new object();
 private static SiteSettings _settings;

 public static SiteSettings SiteApplicationSettings
 {
  get
  {
   if (_settings == null)
    SiteApplicationSettings = SiteSettings.LoadFromConfiguration();
   return _settings;
  }
  set
  {
   if (value == null)
    throw new ArgumentNullException("SiteApplicationSettings cannot be set to null");
   lock (_settingsLock)
   {
    _settings = value;
   }
  }
 }
 public void Application_Start(Object sender, EventArgs e)
 {
  // set-up Settings
  SiteHttpApplication.SiteApplicationSettings = SiteSettings.LoadFromConfiguration();
 }
}
Then, create our "SiteHttpApplication" object in "Global.asax" file.
void Application_Start(object sender, EventArgs e)
{
 // Code that runs on application startup
 SiteHttpApplication siteHttp = new SiteHttpApplication();
 siteHttp.Application_Start(sender, e);
}
Finally, create UI for accessing the xml data as below:
<form id="form1" runat="server">
<div>
    <asp:Panel ID="UpdateErrorPanel" runat="server" Visible="False" EnableViewState="False">
        <p>
            <strong>There was an error writing to the Settings file<br />
                App_Data\site-config.xml.</strong><br />
            Please make sure that the ASP.NET process has write-access to the file.</p>
        <p>
            The textbox below contains the XML equivalent of the Site Settings you saved. You
            can copy it and update the file manually.</p>
        <asp:TextBox ID="SettingsXmlTextBox" runat="server" TextMode="multiLine" Rows="10"
            Width="100%"></asp:TextBox>
    </asp:Panel>
    <fieldset>
        <asp:FormView ID="SettingsFormView" runat="server" DataSourceID="SettingsDataSource"
            DefaultMode="Edit">
            <EditItemTemplate>
                SiteName:
                <asp:TextBox ID="SiteNameTextBox" runat="server" Text='<%# Bind("SiteName") %>' />
                <br />
                SiteVersion:
                <asp:TextBox ID="SiteVersionTextBox" runat="server" Text='<%# Bind("SiteVersion") %>' />
                <br />
                SiteEmailAddress:
                <asp:TextBox ID="SiteEmailAddressTextBox" runat="server" Text='<%# Bind("SiteEmailAddress") %>' />
                <br />
                <br />
                <asp:Button ID="UpdateButton" runat="server" CausesValidation="True" CommandName="Update"
                    Text="Update" />
                &nbsp;<asp:Button ID="UpdateCancelButton" runat="server" CausesValidation="False"
                    CommandName="Cancel" Text="Cancel" />
            </EditItemTemplate>
        </asp:FormView>
        <asp:ObjectDataSource ID="SettingsDataSource" runat="server" TypeName="SiteSettings"
            SelectMethod="GetSharedSettings" UpdateMethod="UpdateSettings" OnUpdated="SettingsDataSource_Updated"
            DataObjectTypeName="SiteSettings"></asp:ObjectDataSource>
    </fieldset>
</div>
</form>
UI will appear as below:
In code-behind, it need to handle the unsuccessful action in OnUpdated event of ObjectDataSource.
protected void SettingsDataSource_Updated(object sender, ObjectDataSourceStatusEventArgs e)
{
      try
      {
            // the UpdateSettings methods returns a boolean success value
            bool updateSuccess = false;
            if (e.ReturnValue != null && e.ReturnValue is bool)
                updateSuccess = (bool)e.ReturnValue;

            if (!updateSuccess)
            {
                 // we failed to save the settings to the settings file
                 // but we can output its Xml equivalent for manual saving:
                 SiteSettings s = SiteSettings.GetSharedSettings();
                 SettingsXmlTextBox.Text = s.GetXml();
                 UpdateErrorPanel.Visible = true;
            }
       }
       catch (Exception ex)
       {
                
       }
}
That's it. Run the application and see the result. Right now, you can access the site configuration data on the fly and can update immediately.


If you got error such as "The type [Class] is ambiguous.", Please see here.