Search...

Saturday, May 25, 2013

Validation in WPF

This example shows how to use an ErrorTemplate and a style trigger to provide visual feedback to inform the user when an invalid value is entered, based on a custom validation rule.

Download

Step 1: Create a WPF Application named ValidationInWPF and create following file structure.


Step 2: Update the xaml of MainWindow as follows. 



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
<Window x:Class="ValidationInWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:model="clr-namespace:ValidationInWPF.Model"
        xmlns:validationRules="clr-namespace:ValidationInWPF.ValidationRules"
        Title="MainWindow" 
        Height="243" 
        Width="652">

    <Window.DataContext>
        <model:Person/>
    </Window.DataContext>

    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary 
                  Source="Style.xaml">
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid Margin="10">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>

        <Label Grid.Column="0" Grid.Row="0" Content="User Id:"/>
        <Label Grid.Column="0" Grid.Row="1" Content="User Name:"/>
        <Label Grid.Column="0" Grid.Row="2" Content="Email:"/>
        <Label Grid.Column="0" Grid.Row="3" Content="Contact # (xxx-xxx-xxxx):"/>
        <Label Grid.Column="0" Grid.Row="4" Content="Date of Birth"/>

        <TextBox Grid.Column="1" Grid.Row="0" Name="txtUserId" Width="150" Height="25" HorizontalAlignment="Left" VerticalAlignment="Top" Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
            <TextBox.Text>
                <Binding Path="UserID" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" Mode="TwoWay">
                    <Binding.ValidationRules>
                        <validationRules:RequiredFieldValidation/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <TextBox Grid.Column="1" Grid.Row="1" Name="txtUserName" Width="150" Height="25" HorizontalAlignment="Left" VerticalAlignment="Top" Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
            <TextBox.Text>
                <Binding Path="Name" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" Mode="TwoWay">
                    <Binding.ValidationRules>
                        <validationRules:RequiredFieldValidation/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <TextBox Grid.Column="1" Grid.Row="2" Name="txtEmail" Width="250" Height="25" HorizontalAlignment="Left" VerticalAlignment="Top"  Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
            <TextBox.Text>
                <Binding Path="EmailID" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" Mode="TwoWay">
                    <Binding.ValidationRules>
                        <validationRules:ValidateEmailAddress/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <TextBox Grid.Column="1" Grid.Row="3" Name="txtContactNo" Width="150" Height="25" HorizontalAlignment="Left" VerticalAlignment="Top" Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
            <TextBox.Text>
                <Binding Path="ContactNumber" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" Mode="TwoWay">
                    <Binding.ValidationRules>
                        <validationRules:ValidateContactNumber/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>

        <DatePicker Grid.Column="1" Grid.Row="4" Name="dpDate" Width="150" Height="25" HorizontalAlignment="Left" VerticalAlignment="Top" Validation.ErrorTemplate="{StaticResource TextBoxErrorTemplate}">
            <DatePicker.Text>
                <Binding Path="DateOfBirth" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True" ValidatesOnExceptions="True" Mode="TwoWay">
                    <Binding.ValidationRules>
                        <validationRules:ValidateAge Min="18" Max="120"/>
                    </Binding.ValidationRules>
                </Binding>
            </DatePicker.Text>
        </DatePicker>

            <Button Grid.Column="2" Grid.Row="5" Name="btnSave" Content="Save" Width="100" Height="25" HorizontalAlignment="Right" Click="btnSave_Click">

        </Button>

    </Grid>
</Window>

Step 3: Update the MainWindow.cs as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace ValidationInWPF
{
    
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.dpDate.SelectedDate = DateTime.Now.AddYears(-20);
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {
            if (!ValidateView())
                MessageBox.Show("Validation failed !");
        }

        /// <summary>
        /// This method is used to validate view.
        /// </summary>
        /// <returns></returns>
        /// <Developer>Kaushik Kumar Mistry</Developer>
        /// <DateCreated>25 May 2013</DateCreated>
        /// <ModifiedBy>...</ModifiedBy>
        /// <ModifiedDate>...</ModifiedDate>
        private Boolean ValidateView()
        {
            BindingExpression bindingExpression;

            bindingExpression = txtUserId.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null)
            {
                bindingExpression.UpdateSource();
                if (bindingExpression.HasError)
                    return false;
            }

            bindingExpression = txtUserName.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null)
            {
                bindingExpression.UpdateSource();
                if (bindingExpression.HasError)
                    return false;
            }

            bindingExpression = txtContactNo.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null)
            {
                bindingExpression.UpdateSource();
                if (bindingExpression.HasError)
                    return false;
            }

            bindingExpression = dpDate.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null)
            {
                bindingExpression.UpdateSource();
                if (bindingExpression.HasError)
                    return false;
            }

            bindingExpression = txtEmail.GetBindingExpression(TextBox.TextProperty);
            if (bindingExpression != null)
            {
                bindingExpression.UpdateSource();
                if (bindingExpression.HasError)
                    return false;
            }

            return true;
        }
    }
}


Step 4: Update the Person.cs as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
using System;
using System.ComponentModel;

namespace ValidationInWPF.Model
{

    public class Person : System.ComponentModel.INotifyPropertyChanged
    {
        #region " Data Member "

        private String name;
        private String strEmailAddress;
        private String strContactNumber;

        #endregion

        /// <summary>
        /// Get or Set the User Id. 
        /// </summary>
        public string UserID { get; set; }

        /// <summary>
        /// Get or Set the Name. 
        /// </summary>
        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
                RaisePropertyChanged("Name");
            }
        }
        
        /// <summary>
        /// Get or Set the Email Id.
        /// </summary>
        public String EmailID
        {
            get
            {
                return this.strEmailAddress;
            }
            set
            {
                this.strEmailAddress = value;
                RaisePropertyChanged("EmailID");
            }
        }

        /// <summary>
        /// Get or Set the Contact Number.
        /// </summary>
        public String ContactNumber
        {
            get 
            { 
                return this.strContactNumber; 
            }
            set
            {
                this.strContactNumber = value;
                RaisePropertyChanged("ContactNumber");
            }
        }

        /// <summary>
        /// Get or Set the Date of Birth.
        /// </summary>
        public DateTime DateOfBirth { get; set; }

        #region " INotifyPropertyChanged Implementation "

        /// <summary>
        /// PropertyChanged Event.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// RaisePropertyChanged Function.
        /// </summary>
        /// <param name="propertyName"></param>
        private void RaisePropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName));

        }

        #endregion

    }
}


Step 5: Update the RequiredFieldValidation.cs as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
using System;
using System.Windows.Controls;

namespace ValidationInWPF.ValidationRules
{
    public class RequiredFieldValidation : ValidationRule
    {

        /// <summary>
        /// Implementation of required field validation. 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="cultureInfo"></param>
        /// <returns></returns>
        /// <Developer>Kaushik Kumar Mistry</Developer>
        /// <DateCreated>25 May 2013</DateCreated>
        /// <ModifiedBy>...</ModifiedBy>
        /// <ModifiedDate>...</ModifiedDate>
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            String strValue = value as String;

            if (String.IsNullOrEmpty(strValue))
                return new ValidationResult(false, "* Required.");

            return new ValidationResult(true, null);
        }
    }
}

Step 6: Update the ValidateAge.cs as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
using System;
using System.Windows.Controls;

namespace ValidationInWPF.ValidationRules
{
    public class ValidateAge : ValidationRule
    {
        private int _min;
        private int _max;

        /// <summary>
        /// Get or Set the min age.
        /// </summary>
        public int Min
        {
            get { return _min; }
            set { _min = value; }
        }

        /// <summary>
        /// Get or Set the max age.
        /// </summary>
        public int Max
        {
            get { return _max; }
            set { _max = value; }
        }

        /// <summary>
        /// Implementation of age validation.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="cultureInfo"></param>
        /// <returns></returns>
        /// <Developer>Kaushik Kumar Mistry</Developer>
        /// <DateCreated>25 May 2013</DateCreated>
        /// <ModifiedBy>...</ModifiedBy>
        /// <ModifiedDate>...</ModifiedDate>
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            try
            {
                DateTime birthday = Convert.ToDateTime(value);
                DateTime now = DateTime.Today;
                int age = now.Year - birthday.Year;

                if (now < birthday.AddYears(age))
                    age--;

                if ((age < Min) || (age > Max))
                {
                    return new ValidationResult(false,"Please enter an age in the range: " + Min + " - " + Max + ".");
                }
                else
                    return new ValidationResult(true, null);
            }
            catch
            {
                return new ValidationResult(false, "Date is not in correct format.");
            }
        }
    }
}

Step 7: Update the ValidateContactNumber.cs as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using System.Text.RegularExpressions;
using System.Windows.Controls;

namespace ValidationInWPF.ValidationRules
{
    public class ValidateContactNumber : ValidationRule
    {
        /// <summary>
        /// Implementation of phone number validation.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="cultureInfo"></param>
        /// <returns></returns>
        /// <Developer>Kaushik Kumar Mistry</Developer>
        /// <DateCreated>25 May 2013</DateCreated>
        /// <ModifiedBy>...</ModifiedBy>
        /// <ModifiedDate>...</ModifiedDate>
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            String strContactNumber = value as String;

            if (String.IsNullOrEmpty(strContactNumber))
                return new ValidationResult(true, null);

            else if (Regex.IsMatch(strContactNumber, @"^\d{3}-?\d{3}-?\d{4}$") == false)
                return new ValidationResult(false, "Invalid Phone number.");

            return new ValidationResult(true, null);
        }
    }
}

Step 8: Update the ValidateEmailAddress.cs as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using System.Text.RegularExpressions;
using System.Windows.Controls;

namespace ValidationInWPF.ValidationRules
{
    public class ValidateEmailAddress : ValidationRule
    {
        /// <summary>
        /// Implementation of email validation.
        /// </summary>
        /// <param name="value"></param>
        /// <param name="cultureInfo"></param>
        /// <returns></returns>
        /// <Developer>Kaushik Kumar Mistry</Developer>
        /// <DateCreated>25 May 2013</DateCreated>
        /// <ModifiedBy>...</ModifiedBy>
        /// <ModifiedDate>...</ModifiedDate>
        public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
        {
            String strEmailAddress = value as String;

            if (String.IsNullOrEmpty(strEmailAddress))
                return new ValidationResult(true, null);

            else if (Regex.IsMatch(strEmailAddress, @"^[A-Za-z0-9_\-\.]+@(([A-Za-z0-9\-])+\.)+([A-Za-z\-])+$") == false)
                return new ValidationResult(false, "Invalid email address.");

            return new ValidationResult(true, null);
        }
    }
}

Step 9: Lastly update the Style.xaml  as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">


    <ControlTemplate x:Key="TextBoxErrorTemplate">
        <DockPanel LastChildFill="True">
            <Label DockPanel.Dock="Right" Foreground="Red" Content="{Binding ElementName=holder, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}"/>
            <Border BorderBrush="Red" BorderThickness="1">
                <AdornedElementPlaceholder Name="holder"/>
            </Border>
        </DockPanel>
    </ControlTemplate>

    <Style TargetType="TextBox">
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="True">
                <Setter Property="ToolTip">
                    <Setter.Value>
                        <Binding Path="(Validation.Errors)[0].ErrorContent" RelativeSource="{x:Static RelativeSource.Self}" />
                    </Setter.Value>
                </Setter>
            </Trigger>
        </Style.Triggers>
    </Style>

</ResourceDictionary>

Thursday, May 16, 2013

Base64 image Encode & Decode

Download

Step 1: Create new protect of type Windows Forms Application and design the form as given below.



Note: Use PictureBox control to display image.
Step 2: Update the Form1.cs as follows.

using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Forms;

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

        private void btnBrowse_Click(object sender, EventArgs e)
        {
            OpenFileDialog fileDialog = new OpenFileDialog();
            // image filters
            fileDialog.Filter = "Image Files(*.jpg; *.jpeg; *.gif; *.bmp)|*.jpg; *.jpeg; *.gif; *.bmp";
            if (fileDialog.ShowDialog() == DialogResult.OK)
            {
                // display image in picture box
                pictureBox1.Image = new Bitmap(fileDialog.FileName);
            }
        }

        private void btnEncode_Click(object sender, EventArgs e)
        {
            textBox1.Text = ImageToBase64(pictureBox1.Image, ImageFormat.Jpeg);
            pictureBox1.Image = null;
        }

        private void btnDecode_Click(object sender, EventArgs e)
        {
         
            pictureBox1.Image = Base64ToImage(textBox1.Text);
        }

        public string ImageToBase64(Image image,ImageFormat format)
        {
            using (MemoryStream ms = new MemoryStream())
            {
                // Convert Image to byte[]
                image.Save(ms, format);
                byte[] imageBytes = ms.ToArray();

                // Convert byte[] to Base64 String
                string base64String = Convert.ToBase64String(imageBytes);
                return base64String;
            }
        }

        public Image Base64ToImage(string base64String)
        {
            // Convert Base64 String to byte[]
            byte[] imageBytes = Convert.FromBase64String(base64String);
            MemoryStream ms = new MemoryStream(imageBytes, 0,
              imageBytes.Length);

            // Convert byte[] to Image
            ms.Write(imageBytes, 0, imageBytes.Length);
            Image image = Image.FromStream(ms, true);
            return image;
        }
    }
}



Wednesday, May 15, 2013

Self Hosting in WCF using c#


What is Self Hosting ?

WCF provides the user to host the service in any application (e.g. console application, Windows form etc.). Very interestingly developer is responsible for providing and managing the life cycle of the host process. Service can also be in-pro i.e. client and service in the same process. Now let's us create the WCF service which is hosted in Console application.

Step 1: 

Create a solution with three projects.
1. SelfHostingWCF (WCF Service Library)
2. Host (Console Application)
3. Client  (Console Application)


Step 2: Delete IService1.cs, Service1.cs from SelfHosttingWCF application and add ICalculator.cs, Calculator.cs and modify App.config file in SelfHosttingWCF application as given below.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <system.web>
    <compilation debug="true" />
  </system.web>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="default" name="SelfHostingWCF.Calculator">

        <endpoint address="basic" binding="basicHttpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.tcp://localhost:8888/Service/tcp" binding="netTcpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.pipe://localhost/Service/pipe" binding="netNamedPipeBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/Service" />
          </baseAddresses>
        </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="default">
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

</configuration>

**********************************************************************

using System.ServiceModel;



namespace SelfHostingWCF
{
    [ServiceContract]
    public interface ICalculator
    {
        [OperationContract]
        int Add(int n1,int n2);
    }
}

**********************************************************************

namespace SelfHostingWCF
{
    public class Calculator : ICalculator
    {

        int ICalculator.Add(int n1, int n2)
        {
            return n1 + n2;
        }
    }
}

**********************************************************************

Step 3: Copy App.config file from SelfHostingWCF application and paste it to Host application and modify it as follows.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <services>
      <service behaviorConfiguration="default" name="SelfHostingWCF.Calculator">

        <endpoint address="basic" binding="basicHttpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.tcp://localhost:8888/Service/tcp" binding="netTcpBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="net.pipe://localhost/Service/pipe" binding="netNamedPipeBinding" contract="SelfHostingWCF.ICalculator" />

        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
        
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="default">
          <serviceMetadata httpGetEnabled="True"/>
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

Step 4: Add two references in Host application first one from Projects 'SelfHostingWCF' and second one from .Net 'System.ServiceModel'  and modify the Program.cs file as follows.

using System;
using System.ServiceModel;

namespace Host
{
    public class Program
    {
        static void Main(string[] args)
        {
            //Create base address dynamically..
            Uri baseAddress = new Uri("http://localhost:8080/Service");

            using (ServiceHost host = new ServiceHost(typeof(SelfHostingWCF.Calculator), baseAddress))//if baseAddress is already declared in App.Config file in such case you do not have need to pass second parameter.
            {
                //Create endpoint dynamically.
                host.AddServiceEndpoint(typeof(SelfHostingWCF.ICalculator), new WSHttpBinding(), "ws");

                foreach (var item in host.Description.Endpoints)
                {
                    Console.WriteLine(item.Address); 
                }

                Console.WriteLine("Servive is up and running at {0}",DateTime.Now.ToShortDateString());
                Console.Read();
            }
        }
    }
}

Step 5: Set the Host application as Start up project and press F5, If every thing goes well you will get this.


Service is hosted, now we need to implement the proxy class for the client. There are different ways of creating the proxy
  1. Using SvcUtil.exe, we can create the proxy class and configuration file with end points.
  2. Adding Service reference to the client application.
  3. Implementing ClientBase<T> class
Of these three methods, Implementing ClientBase<T> is the best practice. If you are using rest two method, we need to create proxy class every time when we make changes in Service implementation. But this is not the case for ClientBase<T>. It will create the proxy only at runtime and so it will take care of everything.

Extend the ClientBase<TChannel> class to create a custom WCF client object that can be used to connect to a service. Typically, the WCF client base class is extended by a tool such as the ServiceModel Metadata Utility Tool (Svcutil.exe) on your behalf. 

The ClientBase<TChannel> class can be used quickly and easily by developers who prefer objects to the use of the interfaces and the System.ServiceModel.ChannelFactory<TChannel> class. In all cases this class wraps or exposes the methods and functionality of the System.ServiceModel.ChannelFactory<TChannel> class and the System.ServiceModel.IClientChannel interface.

Step 6: Add two references in Client application first one from Projects 'SelfHostingWCF' and second one from .Net 'System.ServiceModel'  and modify the Program.cs file as follows.

using System;
using System.ServiceModel;
using System.Threading;
using SelfHostingWCF;

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread.Sleep(1000);
            ICalculator proxy = new ClientProxy(new BasicHttpBinding(BasicHttpSecurityMode.None), new EndpointAddress("http://localhost:8080/Service/basic"));
            //ICalculator proxy = new ClientProxy(new NetTcpBinding(), new EndpointAddress("net.tcp://localhost:8888/Service/tcp"));
            Console.WriteLine("Sum of two numbers... 5+5 =" + proxy.Add(5, 5));
            Console.ReadLine();
        }
    }

    public class ClientProxy : ClientBase<ICalculator>, ICalculator
    {
        public ClientProxy()
        {
        }

        public ClientProxy(string endpointConfigurationName) :
            base(endpointConfigurationName)
        {
        }

        public ClientProxy(string endpointConfigurationName, string remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public ClientProxy(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
            base(endpointConfigurationName, remoteAddress)
        {
        }

        public ClientProxy(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
            base(binding, remoteAddress)
        {
        }

        protected override ICalculator CreateChannel()
        {
            return base.CreateChannel();
        }

        int ICalculator.Add(int n1, int n2)
        {
            return base.Channel.Add(n1, n2);
        }
    }
}

Step 7: Right click on project solution select Properties perform following changes.


Step 8: Press F5










 

Wednesday, May 1, 2013

REST based services in WCF

Consuming cross-domain WCF REST services with Jquery using JSON


Download

Step 1: 

Create a solution with three projects.
1. ServiceLibrary (WCF Service Library)
2. Host (WCF Service Application)
3. Client (ASP.NET Empty Web Application)


Step 2:

Modify the app.config, IService.cs and Service.cs as follows in ServiceLibrary application.


<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true"/>
    <authentication mode="None"/>
  </system.web>

  <system.serviceModel>
    <services>
      <service name="ServiceLibrary.Service1" behaviorConfiguration="DefaultBehavior">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080/service"/>
          </baseAddresses>
        </host>
        <endpoint address="basic" binding="basicHttpBinding" contract="ServiceLibrary.IService1"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
 
    <behaviors>
      <serviceBehaviors>
        <behavior name="DefaultBehavior">
          <serviceMetadata httpGetEnabled="true"/>
          <serviceDebug/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

**********************************************************************

using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace ServiceLibrary
{
    [ServiceContract]
    public interface IService1
    {
        [OperationContract(Name="GetSample")]
        [WebInvoke(Method="GET", UriTemplate = "GetSample?value={value}", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        string GetData(string value);

        [OperationContract(Name="PostSample")]
        [WebInvoke(Method = "POST", UriTemplate = "PostSample/compositeType", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        CompositeType GetDataUsingDataContract(CompositeType compositeType);
    }

    [DataContract]
    public class CompositeType
    {
        bool boolValue = true;
        string stringValue = "Hello ";

        [DataMember]
        public bool BoolValue
        {
            get { return boolValue; }
            set { boolValue = value; }
        }

        [DataMember]
        public string StringValue
        {
            get { return stringValue; }
            set { stringValue = value; }
        }
    }
}

**********************************************************************

using System;
using System.ServiceModel.Activation;

namespace ServiceLibrary
{
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
    public class Service1 : IService1
    {
        public string GetData(String value)
        {
            return String.Format(value);
        }

        public CompositeType GetDataUsingDataContract(CompositeType compositeType)
        {
            return compositeType;
        }
    }
}

**********************************************************************

Step 3:

Do following in Host application.
1. Delete IService1.cs
2. Rename Service1.svc to Service.svc 
3. Open Service.svc and update it as follows

<%@ ServiceHost Language="C#" Debug="true" Service="ServiceLibrary.Service1" CodeBehind="ServiceLibrary.Service1.cs"  %>

4. Select Host application press mouse right click select Add Reference.. navigate to project and select ServiceLibrary and press ok.

5. Select Host application press mouse right click select Add New Item..add Global.asax file in project and update it as follows

protected void Application_BeginRequest(object sender, EventArgs e)
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin", "*");

            if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
            {
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods", "GET,POST");
                HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept");
                HttpContext.Current.Response.End();
            }
        }

6.  Open Web.config and update it as follows


<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0"/>
    <authentication mode="None"/>
  </system.web>
  <system.serviceModel>

    <services>
      <service behaviorConfiguration="DefaultBehavior" name="ServiceLibrary.Service1">
        <endpoint address="json" binding="webHttpBinding" behaviorConfiguration="JsonBehavior" bindingConfiguration="webHttpBindingWithJsonP" contract="ServiceLibrary.IService1"/>
      </service>
    </services>

    <bindings>
      <webHttpBinding>
        <binding name="webHttpBindingWithJsonP"
                 crossDomainScriptAccessEnabled="true" >
        </binding>
      </webHttpBinding>
    </bindings>
 
    <behaviors>
      <endpointBehaviors>
        <behavior name="JsonBehavior">
          <webHttp helpEnabled="true" defaultOutgoingResponseFormat="Json" />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="DefaultBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
        <behavior name="">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="false" />
        </behavior>
      </serviceBehaviors>
    </behaviors>

    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"
      multipleSiteBindingsEnabled="true"/>
 
    <standardEndpoints>
      <webScriptEndpoint>
        <standardEndpoint crossDomainScriptAccessEnabled="true"/>
      </webScriptEndpoint>
      <webHttpEndpoint>
        <standardEndpoint name="" helpEnabled="true" automaticFormatSelectionEnabled="true"/>
      </webHttpEndpoint>
    </standardEndpoints>

  </system.serviceModel>
 
</configuration>

7. Create a folder in Win Drive:\inetpub\wwwroot\RestService

8. Press (Win key) + R type inetmgr press enter.

9. Navigate to RestService press mouse right clickselect Convert To Application.

10. Select Host application press mouse right click select publish..


**********************************************************************

Step 4:

Do following in Client application.
1. Download the latest jquery library from http://jquery.com/download/
2. Select Client application press mouse right click select Add New Item..add a Web Form and update it as follows.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>

<!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>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    </div>
    </form>
</body>
</html>
<script type="text/javascript">
    var json = {BoolValue: true,StringValue: "Hellow World !"};
    json = JSON.stringify(json);

    $(document).ready(function () {

        document.writeln(json + "<br/>");

        $.ajax({
            cache:false,
            url: 'http://localhost/RestService/Service.svc/json/GetSample?value=abcd',
            type: "GET",
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            crossDomain: true,
            success: function (response) {
               alert("GET " + response);
            },
            error: function (xhr) {
                document.writeln("error");
            }
        });

        $.ajax({
            cache: false,
            url: 'http://localhost/RestService/Service.svc/json/PostSample/compositeType',
            data: json,
            processData: true,
            type: "POST",
            dataType: "json",
            contentType: "application/json; charset=utf-8",
            crossDomain: true,
            success: function (response) {
                alert("BoolValue: " + response.BoolValue + " StringValue: " + response.StringValue);
            },
            error: function (xhr) {
                document.writeln("error");
            }
        });

    });
</script>

**********************************************************************

Step 5:

Select Client application and set it as a Start Up project and run the application if every thing goes well you will get following response.

  1. Request URL:
    http://localhost/RestService/Service.svc/json/PostSample/compositeType
  2. Request Method:
    POST
  3. Status Code:
    200 OK
  4. Request Headersview source
    1. Accept:
      application/json, text/javascript, */*
    2. Accept-Charset:
      ISO-8859-1,utf-8;q=0.7,*;q=0.3
    3. Accept-Encoding:
      gzip,deflate,sdch
    4. Accept-Language:
      en-US,en;q=0.8
    5. Connection:
      keep-alive
    6. Content-Length:
      48
    7. Content-Type:
      application/json; charset=UTF-8
    8. DNT:
      1
    9. Host:
      localhost
    10. Origin:
      http://localhost:60412
    11. Referer:
      http://localhost:60412/
    12. User-Agent:
      Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
  5. Request Payloadview source
    {BoolValue:true, StringValue:Hello World !}
    1. BoolValuetrue
    2. StringValue"Hello World !"
    1. Response Headersview source
      1. Access-Control-Allow-Origin:
        *
      2. Cache-Control:
        private
      3. Content-Length:
        48
      4. Content-Type:
        application/json; charset=utf-8
      5. Date:
        Wed, 01 May 2013 17:46:40 GMT
      6. Server:
        Microsoft-IIS/7.5
      7. Set-Cookie:
        ASP.NET_SessionId=m2gaoombumrilv5juh3dimha; path=/; HttpOnly
      8. X-AspNet-Version:
        4.0.30319
      9. X-Powered-By:
        ASP.NET

    And

    1. Request URL:
      http://localhost/RestService/Service.svc/json/GetSample?value=Hello%20World%20!&_=1367430400381
    2. Request Method:
      GET
    3. Status Code:
      200 OK
    4. Request Headersview source
      1. Accept:
        application/json, text/javascript, */*
      2. Accept-Charset:
        ISO-8859-1,utf-8;q=0.7,*;q=0.3
      3. Accept-Encoding:
        gzip,deflate,sdch
      4. Accept-Language:
        en-US,en;q=0.8
      5. Connection:
        keep-alive
      6. Content-Type:
        application/json; charset=utf-8
      7. DNT:
        1
      8. Host:
        localhost
      9. Origin:
        http://localhost:60412
      10. Referer:
        http://localhost:60412/
      11. User-Agent:
        Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.64 Safari/537.31
    5. Query String Parametersview sourceview URL encoded
      1. value:
        Hello World !
      2. _:
        1367430400381
    6. Response Headersview source
      1. Access-Control-Allow-Origin:
        *
      2. Cache-Control:
        private
      3. Content-Length:
        15
      4. Content-Type:
        application/json; charset=utf-8
      5. Date:
        Wed, 01 May 2013 17:46:40 GMT
      6. Server:
        Microsoft-IIS/7.5
      7. Set-Cookie:
        ASP.NET_SessionId=gxoaqee24pubj0jt0qhc4cul; path=/; HttpOnly
      8. X-AspNet-Version:
        4.0.30319
      9. X-Powered-By:
        ASP.NET