Using WCF (Web Service) in Windows Phone, Windows Forms, ASP.NET, Silverlight, Windows 8

In this tutorial, I'm going to show you how to make a simple Windows Communication Foundation (WCF or also called "Web Service", diff) and then use it in Windows Phone, Windows Forms, ASP.NET, Silverlight, or Windows 8.

Shout Out Application

We're going to make a simple Shout Out application and we will be using SQL Server as our backend database, WCF for communicating back and forth into our database and use it in our application.

On the left is the preview of the application that we're going to make.

So what the application does is

  • It can retrieve the latest shouts from the database server
  • It can post your shout
  • Have your own name
What you need
  • An ASP.NET web hosting
  • With SQL SERVER
  • Your favorite SQL Management tools
  • Visual Studio 2010 / Visual Studio 2012

First thing we need to do is to setup our database server

It's important that your database server must be hosted somewhere. Not locally! My database is hosted in GoDadadah.

Let's create a simple table with 4 fields.

  • ID (should be the PK and an Identifier so it automatically increments the ID)
  • Name
  • Shout
  • DatePosted
and name the table as ShoutBox. Then add some records so we can use it later.

Let's now create our Shout Out Service

watch the video

Once you're done with the WCF services. Upload all the files in your ASP.NET web hosting and test it. Here's what it looks like

http://wcf.jaysonragasa.net/ShoutOutService.svc

Here are the classes and interface shown in the video

ShoutOutService

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

using System.Data;
using System.Data.SqlClient;

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "ShoutOutService" in code, svc and config file together.
public class ShoutOutService : IShoutOutService
{
	// our connection string
    string connstr = ConfigurationManager.AppSettings["constr"].ToString();

    /// <summary>
    /// AddShout - add user's shout
    /// </summary>
    /// <param name="name"></param>
    /// <param name="shout"></param>
    public void AddShout(string name, string shout)
    {
        using (SqlConnection sqlconn = new SqlConnection(this.connstr))
        {
            using (SqlCommand cmd = sqlconn.CreateCommand())
            {
                cmd.CommandText = "insert into shoutbox(name, shout, dateposted) values(@thisname, @thisshout, @thisdateposted)";

                cmd.Parameters.Clear();
                cmd.Parameters.Add(new SqlParameter("@thisname", name));
                cmd.Parameters.Add(new SqlParameter("@thisshout", shout));
                cmd.Parameters.Add(new SqlParameter("@thisdateposted", DateTime.Now.ToString()));

                cmd.CommandType = CommandType.Text;
                sqlconn.Open();
                cmd.ExecuteNonQuery();
            }
        }
    }

    /// <summary>
    /// Get all shouts from the users
    /// </summary>
    /// <returns></returns>
    public List<ShoutModel> GetAllShouts()
    {
        List<ShoutModel> result = new List<ShoutModel>();

        using (SqlConnection sqlconn = new SqlConnection(this.connstr))
        {
            using (SqlCommand cmd = sqlconn.CreateCommand())
            {
                cmd.CommandText = "select top 15 name, shout, DatePosted from ShoutBox order by DatePosted DESC";

                cmd.CommandType = CommandType.Text;
                sqlconn.Open();

                using (SqlDataReader reader = cmd.ExecuteReader())
                {
                    while (reader.Read())
                    {
                        result.Add(new ShoutModel()
                        {
                            Name = reader.GetString(reader.GetOrdinal("name")),
                            Shout = reader.GetString(reader.GetOrdinal("shout")),
                            DatePosted = reader.GetDateTime(reader.GetOrdinal("DatePosted")).ToString("MM/dd/yy hh:mm"),
                        });
                    }
                }
            }
        }

        return result;
    }
}

IShoutOutService

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IShoutOutService" in both code and config file together.
[ServiceContract]
public interface IShoutOutService
{
    [OperationContract]
    void AddShout(string name, string shout);

    [OperationContract]
    List<ShoutModel> GetAllShouts();
}

ShoutModel

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization;

/// <summary>
/// Summary description for ShoutModel
/// </summary>
[DataContract]
public class ShoutModel
{
    [DataMember]
    public string Name
    {
        get;
        set;
    }

    [DataMember]
    public string Shout
    {
        get;
        set;
    }

    [DataMember]
    public string DatePosted
    {
        get;
        set;
    }
}

The next step is how to use the WCF service in Windows Phone

watch the video

Here are the codes that were demoed on the video

MainPage.xaml

<phone:PhoneApplicationPage 
    x:Class="ShoutOut.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:controls="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="800"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait"  Orientation="Portrait"
    shell:SystemTray.IsVisible="False">

    <!--LayoutRoot is the root grid where all page content is placed-->
    <Grid x:Name="LayoutRoot" Background="Transparent">
        <!--Pivot Control-->
        <controls:Pivot Title="CAPPLOUD Labs">
            <!--Pivot item one-->
            <controls:PivotItem Header="Shout outs!">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="523*" />
                        <RowDefinition Height="70" />
                    </Grid.RowDefinitions>
                    <StackPanel Margin="0,0,0,0" VerticalAlignment="Stretch">
                        <ListBox x:Name="lbShouts" ItemTemplate="{StaticResource ShoutTemplate}" HorizontalAlignment="Stretch" />
                    </StackPanel>
                    <StackPanel Grid.Row="1" Background="Transparent">
                        <StackPanel x:Name="panelFields" Orientation="Horizontal" Opacity="1">
                            <TextBox x:Name="txShout" HorizontalAlignment="Stretch" Width="327" />
                            <Button x:Name="btnShout" Content="Shout!" />
                        </StackPanel>
                    </StackPanel>
                </Grid>
            </controls:PivotItem>

            <!--Pivot item two-->
            <controls:PivotItem Header="Setting">
                <Grid>
                    <StackPanel>
                        <TextBlock Text="your name" />
                        <TextBox x:Name="txName" />
                    </StackPanel>
                </Grid>
            </controls:PivotItem>
        </controls:Pivot>
    </Grid>
 
    <!--Sample code showing usage of ApplicationBar-->
    <!--<phone:PhoneApplicationPage.ApplicationBar>
        <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
            <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
            <shell:ApplicationBar.MenuItems>
                <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
            </shell:ApplicationBar.MenuItems>
        </shell:ApplicationBar>
    </phone:PhoneApplicationPage.ApplicationBar>-->

</phone:PhoneApplicationPage>

MainPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Phone.Controls;

namespace ShoutOut
{
    public partial class MainPage : PhoneApplicationPage
    {
        ConsumeShoutOutService.ShoutOutServiceClient shoutout;

        // Constructor
        public MainPage()
        {
            InitializeComponent();
            InitializeControlEvents();
            InitializeControls();
        }

        void InitializeControls()
        {
            this.shoutout = new ConsumeShoutOutService.ShoutOutServiceClient();
            this.shoutout.AddShoutCompleted += new EventHandler<System.ComponentModel.AsyncCompletedEventArgs>(shoutout_AddShoutCompleted);
            this.shoutout.GetAllShoutsCompleted += new EventHandler<ConsumeShoutOutService.GetAllShoutsCompletedEventArgs>(shoutout_GetAllShoutsCompleted);

            txName.Text = "User" + DateTime.Now.ToString("MMddhhmm");
        }

        void InitializeControlEvents()
        {
            btnShout.Tap += new EventHandler<GestureEventArgs>(btnShout_Tap);
        }

        void RefreshShoutOutList()
        {
            this.shoutout.GetAllShoutsAsync();
        }

        void btnShout_Tap(object sender, GestureEventArgs e)
        {
            this.shoutout.AddShoutAsync(txName.Text, txShout.Text);
        }

        void shoutout_GetAllShoutsCompleted(object sender, ConsumeShoutOutService.GetAllShoutsCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                lbShouts.ItemsSource = e.Result;
            }
            else
            {
                // something went wrong
                // so do something here too
                System.Diagnostics.Debug.WriteLine(e.Error.Message);
            }
        }

        void shoutout_AddShoutCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
        {
            if (e.Error == null)
            {
                RefreshShoutOutList();
            }
            else
            {
                // something went wrong
                // so do something here too
                System.Diagnostics.Debug.WriteLine(e.Error.Message);
            }
        }

        protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
        {
            RefreshShoutOutList();
        }
    }
}

App.xaml ShoutTemplate for ListBox Item Template

<Application 
    x:Class="ShoutOut.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"       
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone">

    <!--Application Resources-->
    <Application.Resources>
        <DataTemplate x:Name="ShoutTemplate">
            <StackPanel Margin="0,0,0,20" Background="#8000D3BE">
                <StackPanel Orientation="Horizontal">
                    <TextBlock HorizontalAlignment="Left" Text="{Binding Path=Name}" VerticalAlignment="Stretch" Foreground="#FFFFEE00" FontWeight="Bold" Padding="5" />
                    <TextBlock HorizontalAlignment="Right" Text="{Binding Path=DatePosted}" VerticalAlignment="Stretch" Foreground="#FFD1D1D1" Margin="20,0,0,0" Padding="5" />
                </StackPanel>
                <TextBlock HorizontalAlignment="Stretch" Text="{Binding Path=Shout}" VerticalAlignment="Stretch" TextWrapping="Wrap" Padding="5" />
            </StackPanel>
        </DataTemplate>
    </Application.Resources>

    <Application.ApplicationLifetimeObjects>
        <!--Required object that handles lifetime events for the application-->
        <shell:PhoneApplicationService 
            Launching="Application_Launching" Closing="Application_Closing" 
            Activated="Application_Activated" Deactivated="Application_Deactivated"/>
    </Application.ApplicationLifetimeObjects>

</Application>

I hope you learned something on this WCF and Windows Phone tutorial and here's the complete ShoutOut solution that you can study. Part 2 will be using the same WCF service in other Microsoft platforms.

Click here to expand the blog post

So Short! A simple URL shortening service

I just decided earlier in the morning to create one web app before going off to work. It's called So Short! visit the link here So Short!

So Short! is a simple URL shortening service and so simple it has a simple user interface and offers a basic feature such as

  • Your custom name for your link
  • Simple anlytics (currently shows how many hits your link had)

Simple really.

Here are some screen shots

Showing how many hits

Click here to expand the blog post

Spider Guard

Spider Guard is an online security that prevents your website from being crawled by unwanted spider/crawler/screen scrapper (PARASITES!) that just eat your bandwidth and useless for your website ranks.

Spider Guard will be a community project where you can help by sharing IP addresses of suspecious spider servers and submitting them to our blacklist database. An Internal system application will also help.

 

Read here for more information: http://spiderguard.jaysonragasa.net/

Click here to expand the blog post

BlogEngine.NET - WIDGET - Most Viewed Post

I found some few articles regarding this funtionallity in BlogEngine.NET but I'd really like to make my own. So as you can see from that screen shot, I have the widget on the left and sql query from the right. I used SQL Server anyway so if you guys still use XML, this is not for your BE. Well you can still read though to get some ideas.

Am using BE 1.6.1 - this could be compatible with 1.6 or lower version or higher? correct me if I'm wrong.

 

How things works?

Well I added a new table called "be_PostViews" and 2 new Stored Procedure to Update/Insert records and get the TOP 5 most viewed posts. Then I have a new Widget called "MostViewed".

Installation

Here are the SQLs you need for the table and stored procedure

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[be_PostViews](
	[PostID] [nvarchar](50) COLLATE Latin1_General_CI_AS NOT NULL,
	[TotalViews] [int] NOT NULL,
	[DateUpdated] [datetime] NULL,
	[DateCreated] [datetime] NULL,
	[REMOTE_ADDR] [nvarchar](50) COLLATE Latin1_General_CI_AS NULL,
	[HTTP_USER_AGENT] [nvarchar](255) COLLATE Latin1_General_CI_AS NULL,
	[BROWSER_NAME] [nvarchar](50) COLLATE Latin1_General_CI_AS NULL,
	[IS_CRAWLER] [nvarchar](50) COLLATE Latin1_General_CI_AS NULL
) ON [PRIMARY]

-- =============================================
-- Author:		usp_get_most_viewed
-- Create date: 
-- Description:	
-- =============================================
CREATE PROCEDURE [dbo].[usp_get_most_viewed] 
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for procedure here
SELECT TOP 5
	be_Posts.PostID,
	be_Posts.Title,
	be_PostViews.TotalViews,
	be_PostViews.DateUpdated,
	be_PostViews.DateCreated,
	be_PostViews.*
FROM
	be_Posts INNER JOIN
		be_PostViews ON be_Posts.PostID = be_PostViews.PostID
ORDER BY be_PostViews.TotalViews DESC
END

-- =============================================
-- Author:		usp_update_postview
-- Create date: 
-- Description:	
-- =============================================
CREATE PROCEDURE [dbo].[usp_update_postview] 
	-- Add the parameters for the stored procedure here
	@thisPostID nvarchar(50),
	@thisREMOTE_ADDR nvarchar(50),
	@thisHTTP_USER_AGENT nvarchar(255),
	@thisBROWSER_NAME nvarchar(50),
	@thisIS_CRAWLER nvarchar(50)
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    -- Insert statements for procedure here
	IF(EXISTS(SELECT PostID from be_PostViews WHERE PostID = @thisPostID))
		BEGIN
			DECLARE @thisTotalViews int;
			SET @thisTotalViews = (SELECT TotalViews from be_PostViews WHERE PostID = @thisPostID)
			SET @thisTotalViews = @thisTotalViews + 1;

			UPDATE be_PostViews SET
				TotalViews = @thisTotalViews, 
				DateUpdated=GETDATE(),
				REMOTE_ADDR=@thisREMOTE_ADDR,
				HTTP_USER_AGENT=@thisHTTP_USER_AGENT,
				BROWSER_NAME=@thisBROWSER_NAME,
				IS_CRAWLER=@thisIS_CRAWLER
			WHERE PostID=@thisPostID;
		END
	ELSE
		BEGIN
			INSERT INTO be_PostViews(
				PostID, 
				TotalViews, 
				DateCreated, 
				DateUpdated,
				REMOTE_ADDR,
				HTTP_USER_AGENT,
				BROWSER_NAME,
				IS_CRAWLER
			)
			VALUES(
				@thisPostID, 
				1, GETDATE(), GETDATE(),
				@thisREMOTE_ADDR,
				@thisHTTP_USER_AGENT,
				@thisBROWSER_NAME,
				@thisIS_CRAWLER
			);
		END

	SELECT TotalViews from be_PostViews WHERE PostID = @thisPostID
END

And for the Widget. It's basically just a control binding. Code is very basic. You do not really need extensive codes for this kind of feature. I'll just show you what's inside. You can just download it later.

This is the .ascx code which has 2 SqlDataSource. 1 for binding to Repeater control, and the other is for Inserting/Updating record in be_PostViews

<asp:SqlDataSource ID="SqlDataSource1" runat="server" 
    ConnectionString="<%$ ConnectionStrings:BlogEngine %>" 
    SelectCommand="usp_get_most_viewed" SelectCommandType="StoredProcedure">
</asp:SqlDataSource>

<asp:Repeater ID="Repeater1" runat="server">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li><span><a href="post.aspx?id=<%# Eval("PostID") %>"><%# Eval("Title") %></a><br/><i><%# Eval("DateUpdated") %></i></span></li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>

<asp:SqlDataSource ID="SqlDataSource2" runat="server" 
    ConnectionString="<%$ ConnectionStrings:BlogEngine %>" 
    SelectCommand="usp_update_postview" SelectCommandType="StoredProcedure">
</asp:SqlDataSource

This is the Code Behind for that widget. You don't have to touch any codes or pages in BlogEngine.NET, everything is done is this widget.

protected override void OnPreRender(EventArgs e)
{
	Repeater1.DataSource = SqlDataSource1;
	Repeater1.DataBind();

	base.OnPreRender(e);
}

protected void Page_Load(object sender, EventArgs e)
{
	object id = Request.QueryString["id"];
	if (id != null)
	{
		pid = id.ToString();
		System.Diagnostics.Debug.WriteLine("widget: " + id.ToString());

		string ipaddress = string.Empty;
		string browseragent = string.Empty;
		string browsername = string.Empty;
		string iscrawler = string.Empty;

		ipaddress = Request.ServerVariables["REMOTE_ADDR"];
		browseragent = Request.ServerVariables["HTTP_USER_AGENT"];
		browsername = Request.Browser.Browser;
		iscrawler = Request.Browser.Crawler.ToString();

		SqlDataSource2.SelectParameters.Add("thisPostID", System.Data.DbType.String, pid);
		SqlDataSource2.SelectParameters.Add("thisREMOTE_ADDR", System.Data.DbType.String, ipaddress);
		SqlDataSource2.SelectParameters.Add("thisHTTP_USER_AGENT", System.Data.DbType.String, browseragent);
		SqlDataSource2.SelectParameters.Add("thisBROWSER_NAME", System.Data.DbType.String, browsername);
		SqlDataSource2.SelectParameters.Add("thisIS_CRAWLER", System.Data.DbType.String, iscrawler);
		System.Data.DataView dataview = (System.Data.DataView)SqlDataSource2.Select(DataSourceSelectArguments.Empty);
	}
}

If you think you can enhace some of the codes then I'd like to hear about it.

Post your questions here: http://blogengine.codeplex.com/discussions/262756

Download the code here: Most Viewed Widget.7z (2.11 kb)

Click here to expand the blog post

ASP.NET My SessionManager

I have written a, I think a clean way to use Session names and values. I honestly hate writing the session name everytime I have to use them and it sometimes leads to mistyping the name. So I made this one to prevent some errors.

[code:c#;ln:off;alt:off;qwe]using System;
using System.Collections;
using System.Collections.Generic;
using System.Web;
using System.Web.SessionState;

public class SessionManager : IRequiresSessionState
{
    public SessionManager()
    {
    }

    public static bool IsUserAuthenticated
    {
        get { return System.Web.HttpContext.Current.User.Identity.IsAuthenticated; }
    }

    #region methods
    public static void ClearSession()
    {
        HttpContext.Current.Session.Clear();
    }

    public static void Save(string name, object value)
    {
        if (HttpContext.Current.Session[name] != null)
        {
            HttpContext.Current.Session[name] = value;
        }
        else
        {
            HttpContext.Current.Session.Add(name, value);
        }
    }

    public static object Get(string name)
    {
        return HttpContext.Current.Session[name];
    }
    #endregion
}[/code]

 

what you think?

Click here to expand the blog post

Welcome to BlogEngine.NET 1.6 using Microsoft SQL Server

If you see this post it means that BlogEngine.NET 1.6 is running with SQL Server and the DbBlogProvider is configured correctly.

Setup

If you are using the ASP.NET Membership provider, you are set to use existing users. If you are using the default BlogEngine.NET XML provider, it is time to setup some users. Find the sign-in link located either at the bottom or top of the page depending on your current theme and click it. Now enter "admin" in both the username and password fields and click the button. You will now see an admin menu appear. It has a link to the "Users" admin page. From there you can change the username and password.

Write permissions

Since you are using SQL to store your posts, most information is stored there. However, if you want to store attachments or images in the blog, you will want write permissions setup on the App_Data folder.

On the web

You can find BlogEngine.NET on the official website. Here you will find tutorials, documentation, tips and tricks and much more. The ongoing development of BlogEngine.NET can be followed at CodePlex where the daily builds will be published for anyone to download.

Good luck and happy writing.

The BlogEngine.NET team

Click here to expand the blog post

About Jayson Ragasa

Jayson Ragasa is an Applications Developer and founder of CAPPLOUD.

Badges

Free Page Rank Tool

wall.jaysonragasa.net Webutation
Uptime Report for http://wall.jaysonragasa.net/: Last 30 days