C#: Save a Form’s Size and Location

In an attempt to enhance user experience it may be desirable to save the size and location of a Form. When dealing with customizable user settings, it is important to determine where to persist the user’s applications settings. The Application class has a UserAppDataRegistry property that references the HKEY_CURRENT_USER\Software\[Control.CompanyName]\[Control.ProductName]\[Control.ProductVersion]. registry key in the user’s profile (If this key does not exist it is created). Here is a basic example of storing a form’s state in the user’s registry profile:
	private void Form_Load(object sender, EventArgs e)
        {
            this.WindowState = (FormWindowState)FormWindowState.Parse(WindowState.GetType(), Application.UserAppDataRegistry.GetValue("WindowState", FormWindowState.Normal).ToString());
            if (this.WindowState == FormWindowState.Normal)
            {
                int x = (int)Application.UserAppDataRegistry.GetValue("LocationX");
                int y = (int)Application.UserAppDataRegistry.GetValue("LocationY");
                this.DesktopLocation = new Point(x, y);
                int w = (int)Application.UserAppDataRegistry.GetValue("WindowSizeW");
                int h = (int)Application.UserAppDataRegistry.GetValue("WindowSizeH");
                this.Size = new Size(w, h);
            }
        }

        private void Form_FormClosing(object sender, FormClosingEventArgs e)
        {
            Application.UserAppDataRegistry.SetValue("WindowState", this.WindowState);
            Application.UserAppDataRegistry.SetValue("WindowSizeH", this.Size.Height);
            Application.UserAppDataRegistry.SetValue("WindowSizeW", this.Size.Width);
            Application.UserAppDataRegistry.SetValue("LocationX", this.DesktopLocation.X);
            Application.UserAppDataRegistry.SetValue("LocationY", this.DesktopLocation.Y);
        }

Microsoft Dynamics Nav: Adding a Record through Web Services

Microsoft Dynamics Nav Web Services can not only read data, but they can also write data to a Microsoft Dynamics Nav database. This example demonstrates adding a record into a Microsoft Dynamics Nav database through Web Services using an XMLPort.

Microsoft Dynamics Nav: Adding a Record through Web Services

1. Create and XMLPort for transferring the data. Note: For this example the MaxOccurs property of the element should be set to ‘One’ to set a “one record limit”. It is possible to set multiple records

1.Create and XMLPort for transferring the data.

2. Create a CodeUnit and add functions that will be used to through the Web Service

GetCustomers(CustomerCode : Code[10];VAR CustXML : XMLport GetSetCustomer) Customer.SETRANGE("No.", CustomerCode); CustXML.SETTABLEVIEW(Customer); SetCustomers(VAR CustXML : XMLport GetSetCustomer) : Integer // Return 1 if import was successful IF CustXML.IMPORT THEN EXIT(1) ELSE EXIT(0);

3. Publish the CodeUnit as a Web Service

3.Publish the CodeUnit as a Web Service

4. Create a .NET Application and register the Microsoft Dynamics Nav Web Service

5. Create the code that interacts with the registered Web Service (Note: This code is for basic demonstration only and additional coding practices should be applied for production code)

        GetSetCustomers_Binding ws;

        private void Form1_Load(object sender, EventArgs e)
        {
            ws = new GetSetCustomers_Binding();
            ws.UseDefaultCredentials = true;
            ws.Url = "http://localhost:7047/DynamicsNAV/WS/CRONUS%20USA,%20Inc./Codeunit/GetSetCustomers";

        }

        private void btnGet_Click(object sender, EventArgs e)
        {
            Customer cust = new Customer();
            Customers cs = new Customers();
            // in nav the XML should be set to maxoccurence of 1 so that we only return one 
            //customer
            ws.GetCustomers(txtNo.Text, ref cs);

            cust = cs.Customer[0];
            txtName.Text = cust.Name;
            txtPhone.Text = cust.Phone_No_;
            txtContact.Text = cust.Contact;
        }

        private void btnSet_Click(object sender, EventArgs e)
        {
            Customers cs = new Customers();
            Customer cust = new Customer();
            List<Customer> custlist = new List<Customer>();

            cust.No_ = txtNo.Text;
            cust.Name = txtName.Text;
            cust.Phone_No_ = txtPhone.Text;
            cust.Contact = txtContact.Text;
            custlist.Add(cust);
            cs.Customer = custlist.ToArray();

            if (ws.SetCustomers(ref cs) == 0)
            {
                MessageBox.Show("No Good.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            };
        }

The sample application referenced in this post can be downloaded >>>here<<<.

View the following posts for additional examples:

Microsoft Dynamics Nav: Retrieving a set of Records through Web Services

Microsoft Dynamics Nav: Using an XMLPort as a .NET DataSource

Microsoft Dynamics Nav: Retrieving a set of Records through Web Services

In a previous post ( Microsoft Dynamics Nav: Using an XMLPort as a .NET DataSource and Microsft Dynamics Nav: Export XMLPort to File) I had demonstrated how to return a set of records, using Web Services, from Microsoft Dynamics Nav with an XMLPort as a dataset.

Microsoft Dynamics Nav: Retrieving a set of Records through Web Services

The following example demonstrates returning a filtered set of records from Microsoft Dynamics Nav through Services.

 

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        GetCustomers_Binding ws;
        Customers customers;
        BindingSource bs;

        private void Form1_Load(object sender, EventArgs e)
        {
            ws = new GetCustomers_Binding();
            ws.UseDefaultCredentials = true;
            ws.Url = "http://localhost:7047/DynamicsNAV/WS/CRONUS%20USA,%20Inc./Codeunit/GetCustomers";

            customers = new Customers();
            bs = new BindingSource();

            BindData(textBox1.Text);
        }

        private void BindData(string salespersoncode)
        {
            ws.GetCustomers(salespersoncode, ref customers);
            dataGridView1.DataSource = bs;
            bs.DataSource = customers.Customer;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            BindData(textBox1.Text);
        }
    }

GetCustomers(SalesPerson : Code[10];VAR CustXML : XMLport Customer_Export) IF SalesPerson <> '' THEN Customer.SETRANGE("Salesperson Code",'PS'); CustXML.SETTABLEVIEW(Customer);

The sample application referenced in this post can be downloaded >>>here<<<.

Microsoft Dynamics Nav: Using an XMLPort as a .NET DataSource

I previously discussed connecting to Microsoft Dynamics Nav using a Web Service and also discussed using an XMLPort to create an XML file. Building upon these concepts we can use a Microsoft Dynamics Nav XMLPort as a DataSource for a .NET application. I recommend reading the previous posts before continuing with this one.

Microsoft Dynamics Nav: Using an XMLPort as a .NET DataSource

This example slightly expands on the previous example and uses the Customer XMLPort as the datasource.

  1. Ensure that the MaxOccurance property is set for the Text element Open_Balance.
    XMLPort Designer
  2. Create a CodeUnit with a Function that uses the XMLPort as a parameter. Ensure that the parameter is marked as a Var parameter.
    CodeUnit Function
  3. Publish the CodeUnit as a Web Service from within Microsoft Dynamics Nav and restart the “Microsoft Dynamics Nav Web Services” service.
    Microsoft Dynamics Nav Web Service
  4. Create a new .NET Application and add the Web Reference for the CustomerExport CodeUnit published as a Web Service
  5. Place a DataGridView on the form
  6. Set the DataSource for the DataGridView to be the Microsoft Dynamics Nav XMLPort
    private void Form1_Load(object sender, EventArgs e)
            {
                CustomerExport_Binding ws = new CustomerExport_Binding();
                ws.UseDefaultCredentials = true;
                ws.Url = "http://localhost:7047/DynamicsNAV/WS/CRONUS%20USA,%20Inc./Codeunit/CustomerExport";
    
                Customers customers = new Customers();
                ws.ExportCustomer(ref customers);
                
                BindingSource bs = new BindingSource();
                dataGridView1.DataSource = bs;
    
                bs.DataSource = customers.Customer;
            }
    

A Microsoft Dynamics Nav XMLPort can easily also be the datasource for a DataGrid in an ASP.NET application.

The sample application referenced in this post can be downloaded >>>here<<<.

C#: ASP.NET CAPTCHA

As easy as it is to develop a web form that accepts user input, it is just as easy to develop an automated application that can fill the web form with data. In an attempt defend against these applications; web authors often implement a challenge-response mechanism to verify that the web form has been completed by a “human”. This challenge-response mechanism is commonly referred to as CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart). The key to a CAPTCHA mechanism is to make it easy for humans and difficult for “computers” to solve. One popular method is to generate random text for a human to enter as part of the data entry process.

CAPTCHA

There are many commercial and free CAPTCHA plugins available for use, but you can easily create a CAPTCHA as part of your web application. To incorporate your own CAPTCHA mechanism into your web form:

– Add a method to generate the “random text”

public void SetCAPTCHAText()
    {
        // generate a random number
        Random ran = new Random();
        int no = ran.Next(11111, 99999);
        // store the random number in a session variable
        Session["Captcha"] = no.ToString();
    }

Add a method to validate the “random text” with user input

protected void CAPTCHAValidate(object source, ServerValidateEventArgs args)
    {

        if (Session["Captcha"] != null)
        {
            if (txtVerify.Text.ToUpper() != Session["Captcha"].ToString().ToUpper())
            {
                SetCAPTCHAText();
                args.IsValid = false;
                return;
            }
        }
        else
        {
            SetCAPTCHAText();
            args.IsValid = false;
            return;
        }

    }

– Add a new Generic Handler to your Web Site to draw the image containing the “random text”

Generic Handler

public void ProcessRequest(HttpContext context)
    {
        //factor for scaling
        int factor = 25;

        // set the size of the image
        int imagewidth = 150;
        int imageheight = 30;

        // setup the image
        Bitmap bmpOut = new Bitmap(imagewidth, imageheight);
        Graphics g = Graphics.FromImage(bmpOut);
        g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
        g.FillRectangle(Brushes.White, 0, 0, imagewidth, imageheight);

        // draw the verification code on the image
        Color c = new Color();
        c = Color.Black;
        Font f = new Font("Verdana", 14);
        SolidBrush b = new SolidBrush(c);
        if (!String.IsNullOrEmpty(System.Web.HttpContext.Current.Session["Captcha"].ToString()))
        {
            g.DrawString(System.Web.HttpContext.Current.Session["Captcha"].ToString(), f, b, 5, 5);
        }

        // draw some random data to image to distort OCR
        Random rnd = new Random();
        int m = imagewidth / factor;
        for (int i = 0; i &lt;= Convert.ToInt32(Math.Truncate(bmpOut.Width * bmpOut.Height / (double)factor)) - 1; i++)
        {
            int x = rnd.Next(bmpOut.Width);
            int y = rnd.Next(bmpOut.Height);
            int w = rnd.Next(m);
            int h = rnd.Next(m);
            g.FillEllipse(Brushes.Gray, x, y, w, h);
            
            // you could get creative with other "noise"
            //Point[] points = { new Point(100, 25), new Point(90, 20), new Point(110, 15), new Point(85, 15) };
            //g.FillClosedCurve(Brushes.Red, points);
        }

        // write the image to the stream for display on the webpage
        MemoryStream ms = new MemoryStream();
        bmpOut.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        byte[] bmpBytes = ms.GetBuffer();
        bmpOut.Dispose();
        g.Dispose();
        ms.Close();
        context.Response.BinaryWrite(bmpBytes);
        context.Response.End();
    }

    public bool IsReusable
    {
        get
        {
            return false;
        }
    }

– Add an image to the web form to display the CAPTCHA text – the image is drawn by the Handler
– Add a text box for the user input
– Validate the user input when the user submits the form

 


<div>
    <asp:Image ID="imCaptcha" ImageUrl="~/Captcha.ashx" runat="server" />
     <asp:TextBox ID="txtVerify" runat="server"></asp:TextBox>
     <asp:CustomValidator ID="CustomValidator2" runat="server" ControlToValidate="txtVerify" ErrorMessage="Invalid verification code entered." OnServerValidate="CAPTCHAValidate" SetFocusOnError="True" ValidateEmptyText="True" ToolTip="Invalid verification code entered.">*</asp:CustomValidator>
    <asp:Label ID="Label4" runat="server" Text="Enter the number displayed above."></asp:Label>
    <asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert" Text="Submit" />
    <asp:ValidationSummary ID="ValidationSummary1" runat="server" />
</div>

 

The sample application referenced in this post can be downloaded >>>here<<<.