Stuff You Will Need (Other than the dev tools)
- A host to serve your service
- A registered domain with said host
- An FTP client
I use TSOHost for all my web hosting, have my domain registered with them and they also serve my web site there. I chose these guys as at the time they gave all I needed in there basic package for ASP.NET and must say I have not a bad word to say about them. Any tech issues I have had; they have responded and resolved in no time at all. Now if I was you, I wouldn’t just take these guys up, I would have a good look round first, make sure you get a good deal.
Create Database
So once you are registered, have your domain up and running, you will want to set up a DB on the server, now I can only show you how I do it with the host I use, it will differ if you use another company to host your site.
From the dashboard the host provide me with I can get to my MySQL DB stuff and set up a new DB
This then gives me the server side IP address for the database so I can then connect to it from my service, we will need this later, don’t worry about it for now, just know we will need it later.
I now need to set up a user for this DB, again from the control panel the host has provided I can do this.
Now we have a database and a user that can access it, what we now need is a table that can be used to store data. Again from the hosts dashboard I can go and create a table in my new DB
Now with the table created I need to create the columns that will be in it.
So, my two columns are Country and Count. So we now have a table set up which will look something like this
Service Creation
Now we need to create a web service to be hosted from our site and have access to the new DB and it’s table(s). We will also have to get some assemblies so we can connect and use a MySQL database, but lets get the basic service project going for now.
Open up VS2010 and create a new Web Site,
As far as creating a WCF web service, you have just done it; it wont do what you want it to yet, but the default project comes with basic stubs so you could run it as it stands and it would run the service. But we don’t want that…
Creating Web Methods
So, we now want to give the service some methods so we can act on the database. First thing I am going to do is rename the source files to reflect this service better.
I am also going to clear out all the stuff we don’t need from this project, all the template code can go really, so in the IRCTestService.cs (was IService.cs) I am removing everything from line 23 on wards, we wont be needing that data contract, we will create our own ones in a moment. I am also going to remove ALL the operational contracts from the interface in this file too, we now have a pretty naked looking file
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService" in both code and config file together.
[ServiceContract]
public interface IRCTestService
{
}
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService" in both code and config file together.
[ServiceContract]
public interface IRCTestService
{
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service" in code, svc and config file together.
public class RCTestService : IRCTestService
{
}
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the class name "Service" in code, svc and config file together.
public class RCTestService : IRCTestService
{
}
<%@ ServiceHost Language="C#" Debug="true" Service="RCTestService" CodeBehind="~/App_Code/RCTestService.cs" %>
In this class I am going to have it store a user name and password, we won’t really be doing much validation as this is a simple project, but just to show you how you might want to set it up. So your RequestBase class should now look like this, note you have to specify that the members are Data Members
[DataContract]
public class RequestBase
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public string Password { get; set; }
public RequestBase()
{
//
// TODO: Add constructor logic here
//
}
}
public class RequestBase
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public string Password { get; set; }
public RequestBase()
{
//
// TODO: Add constructor logic here
//
}
}
[DataContract]
public class UpdateRequest : RequestBase
{
[DataMember]
public string Country { get; set; }
public UpdateRequest()
{
//
// TODO: Add constructor logic here
//
}
}
public class UpdateRequest : RequestBase
{
[DataMember]
public string Country { get; set; }
public UpdateRequest()
{
//
// TODO: Add constructor logic here
//
}
}
[ServiceContract]
public interface IRCTestService
{
[OperationContract]
void UpdateServer(UpdateRequest request);
}
public interface IRCTestService
{
[OperationContract]
void UpdateServer(UpdateRequest request);
}
public class RCTestService : IRCTestService
{
public void UpdateServer(UpdateRequest request)
{
if (ValidRequest(request))
{
// Do what we need to do
}
}
private bool ValidRequest(RequestBase request)
{
return true;
}
}
{
public void UpdateServer(UpdateRequest request)
{
if (ValidRequest(request))
{
// Do what we need to do
}
}
private bool ValidRequest(RequestBase request)
{
return true;
}
}
Hit OK, it’s so we can debug the service, we can remove this later, it just adds a setting to the web.config file. So you should then get a screen a little like this
If you get a screen like this
Click the RDTestService.svc file, this is the actual service we want to make sure runs.
Congratulations you have just written your own WCF service!! Still does not do all we need though, and now we will look at how we will interact with the database :)
MySQL
So, we now need to get the MySQL assemblies so we can connect to the DB, you can find the download you needhere. Download and install the msi, I had to uninstall an older version, you may need to do the same.
Once installed you can then reference the MySQL assemblies in your project, right click on the project and select Add Reference like this
In the Add Reference popup, select the .NET tab, wait about 9 hours (not that long really :P) then go find the MySQL.Data reference and add that to your project like this
Now we have registered the MySQL assemblies we can go on to create a class that will handle all our communications with the database. In the App_Code folder create a Utilities folder, in there create a class called DBUtility and add using statements for System.Data, MySql.Data and MySql.Data.MySqlClient like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using MySql.Data;
using MySql.Data.MySqlClient;
/// <summary>
/// Summary description for DBUtility
/// </summary>
public class DBUtility
{
public DBUtility()
{
//
// TODO: Add constructor logic here
//
}
}
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using MySql.Data;
using MySql.Data.MySqlClient;
/// <summary>
/// Summary description for DBUtility
/// </summary>
public class DBUtility
{
public DBUtility()
{
//
// TODO: Add constructor logic here
//
}
}
public class DBUtility
{
public IDbConnection CNN;
public DBUtility(string server,string port, string database,string userID,string password)
{
CNN = new MySqlConnection(string.Format("Data Source={0};Port={1};Database={2};User ID={3};Password={4}", server, port, database, userID, password));
}
public DataSet GetDataSet(string sql)
{
DataSet ds = new DataSet();
IDbDataAdapter da;
da = new MySqlDataAdapter(sql, (MySqlConnection)CNN);
da.Fill(ds);
return ds;
}
}
{
public IDbConnection CNN;
public DBUtility(string server,string port, string database,string userID,string password)
{
CNN = new MySqlConnection(string.Format("Data Source={0};Port={1};Database={2};User ID={3};Password={4}", server, port, database, userID, password));
}
public DataSet GetDataSet(string sql)
{
DataSet ds = new DataSet();
IDbDataAdapter da;
da = new MySqlDataAdapter(sql, (MySqlConnection)CNN);
da.Fill(ds);
return ds;
}
}
So, now we have all this set up we can code up our web method to update the table for us. To the RCTestService.cs we are going to add an instance of DBUtility, in the service constructor, initiate it and then use it in our web method to update the database. In order to do this we are going to set up some values in the web.config file, we are going to add an appSettings section and give it two keys, Server and Port like this
<?xml version="1.0"?>
<configuration>
<appSettings>
<add key="Server" value=""/>
<add key="Port" value=""/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="MySql.Data, Version=6.4.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"/>
</assemblies>
</compilation>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
<configuration>
<appSettings>
<add key="Server" value=""/>
<add key="Port" value=""/>
</appSettings>
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="MySql.Data, Version=6.4.4.0, Culture=neutral, PublicKeyToken=C5687FC88969C44D"/>
</assemblies>
</compilation>
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior>
<!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
<serviceMetadata httpGetEnabled="true"/>
<!-- To receive exception details in faults for debugging purposes, set the value below to true. Set to false before deployment to avoid disclosing exception information -->
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<serviceHostingEnvironment multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>
</configuration>
So, now we have our server and port configured we can set up the connection object in the service constructr like this
public class RCTestService : IRCTestService
{
protected DBUtility dbUtil;
public RCTestService()
{
dbUtil = new DBUtility(ConfigurationManager.AppSettings["Server"], ConfigurationManager.AppSettings["Port"], "randomch_testdb", "randomch_test", "test");
}
{
protected DBUtility dbUtil;
public RCTestService()
{
dbUtil = new DBUtility(ConfigurationManager.AppSettings["Server"], ConfigurationManager.AppSettings["Port"], "randomch_testdb", "randomch_test", "test");
}
public void UpdateServer(UpdateRequest request)
{
if (ValidRequest(request))
{
// Do we have any of this country?
string sql = string.Format("SELECT * FROM TestTable WHERE Country = '{0}'", request.Country);
DataSet ds = dbUtil.GetDataSet(sql);
// Update DB
if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
sql = string.Format("UPDATE TestTable SET Count = {1} WHERE Country = '{0}'", request.Country, int.Parse(ds.Tables[0].Rows[0]["Count"].ToString()) + 1);
else
sql = string.Format("INSERT INTO TestTable VALUES('{0}',{1})", request.Country, 1);
dbUtil.GetDataSet(sql);
}
}
{
if (ValidRequest(request))
{
// Do we have any of this country?
string sql = string.Format("SELECT * FROM TestTable WHERE Country = '{0}'", request.Country);
DataSet ds = dbUtil.GetDataSet(sql);
// Update DB
if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
sql = string.Format("UPDATE TestTable SET Count = {1} WHERE Country = '{0}'", request.Country, int.Parse(ds.Tables[0].Rows[0]["Count"].ToString()) + 1);
else
sql = string.Format("INSERT INTO TestTable VALUES('{0}',{1})", request.Country, 1);
dbUtil.GetDataSet(sql);
}
}
We can also add a new web method now to get us all the data in the table so we ca display it on our client. Before we do this we need to create a decent response object so we can bundle all that data up and pass it back to the client in a nice tidy manner. We do this with another data contract, but first we will create a ResponseBase and then derive from that.
As before in the DataContracts folder create a new class, but this time call it ResponseBase like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
/// <summary>
/// Summary description for ResponseBase
/// </summary>
[DataContract]
public class ResponseBase
{
[DataMember]
public bool Success { get; set; }
[DataMember]
public string Message { get; set; }
public ResponseBase()
{
Success = true;
}
}
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
/// <summary>
/// Summary description for ResponseBase
/// </summary>
[DataContract]
public class ResponseBase
{
[DataMember]
public bool Success { get; set; }
[DataMember]
public string Message { get; set; }
public ResponseBase()
{
Success = true;
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService" in both code and config file together.
[ServiceContract]
public interface IRCTestService
{
[OperationContract]
ResponseBase UpdateServer(UpdateRequest request);
}
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name "IService" in both code and config file together.
[ServiceContract]
public interface IRCTestService
{
[OperationContract]
ResponseBase UpdateServer(UpdateRequest request);
}
public ResponseBase UpdateServer(UpdateRequest request)
{
ResponseBase retVal = new ResponseBase();
try
{
throw new Exception("oops");
if (ValidRequest(request))
{
// Do we have any of this country?
string sql = string.Format("SELECT * FROM TestTable WHERE Country = '{0}'", request.Country);
DataSet ds = dbUtil.GetDataSet(sql);
// Update DB
if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
sql = string.Format("UPDATE TestTable SET Count = {1} WHERE Country = '{0}'", request.Country, int.Parse(ds.Tables[0].Rows[0]["Count"].ToString()) + 1);
else
sql = string.Format("INSERT INTO TestTable VALUES('{0}',{1})", request.Country, 1);
dbUtil.GetDataSet(sql);
}
else
{
retVal.Success = false;
retVal.Message = "Invalid Request Credentials!";
}
}
catch (Exception e)
{
retVal.Success = false;
retVal.Message = e.Message;
}
return retVal;
}
{
ResponseBase retVal = new ResponseBase();
try
{
throw new Exception("oops");
if (ValidRequest(request))
{
// Do we have any of this country?
string sql = string.Format("SELECT * FROM TestTable WHERE Country = '{0}'", request.Country);
DataSet ds = dbUtil.GetDataSet(sql);
// Update DB
if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
sql = string.Format("UPDATE TestTable SET Count = {1} WHERE Country = '{0}'", request.Country, int.Parse(ds.Tables[0].Rows[0]["Count"].ToString()) + 1);
else
sql = string.Format("INSERT INTO TestTable VALUES('{0}',{1})", request.Country, 1);
dbUtil.GetDataSet(sql);
}
else
{
retVal.Success = false;
retVal.Message = "Invalid Request Credentials!";
}
}
catch (Exception e)
{
retVal.Success = false;
retVal.Message = e.Message;
}
return retVal;
}
Create a new folder called DataObjects, in there create a class called TableData like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
/// <summary>
/// Summary description for TableData
/// </summary>
public class TableData
{
public string Country { get; set; }
public int Count { get; set; }
public TableData()
{ }
public TableData(string country, int count)
{
Country = country;
Count = count;
}
public TableData(DataRow row)
{
Country = row["Country"].ToString();
int c = 0;
int.TryParse(row["Count"].ToString(), out c);
Count = c;
}
}
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
/// <summary>
/// Summary description for TableData
/// </summary>
public class TableData
{
public string Country { get; set; }
public int Count { get; set; }
public TableData()
{ }
public TableData(string country, int count)
{
Country = country;
Count = count;
}
public TableData(DataRow row)
{
Country = row["Country"].ToString();
int c = 0;
int.TryParse(row["Count"].ToString(), out c);
Count = c;
}
}
Now again, create a new class in the DataContracts folder called GetAllResponse deriving from ResponseBase like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Data;
/// <summary>
/// Summary description for GetAllResponse
/// </summary>
[DataContract]
public class GetAllResponse : ResponseBase
{
[DataMember]
IList<TableData> Data { get; set; }
public GetAllResponse()
{ }
public GetAllResponse(DataRowCollection rows)
{
Data = new List<TableData>();
foreach (DataRow row in rows)
Data.Add(new TableData(row));
}
}
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;
using System.Data;
/// <summary>
/// Summary description for GetAllResponse
/// </summary>
[DataContract]
public class GetAllResponse : ResponseBase
{
[DataMember]
IList<TableData> Data { get; set; }
public GetAllResponse()
{ }
public GetAllResponse(DataRowCollection rows)
{
Data = new List<TableData>();
foreach (DataRow row in rows)
Data.Add(new TableData(row));
}
}
Now we can create our new Web method to get it all for us, in the interface, set up the call like this
[OperationContract]
GetAllResponse GetAll(RequestBase request);
GetAllResponse GetAll(RequestBase request);
public GetAllResponse GetAll(RequestBase request)
{
GetAllResponse retVal = new GetAllResponse();
try
{
if (ValidRequest(request))
{
// Do our SQL stuff here
}
else
{
retVal.Success = false;
retVal.Message = "Invalid Request Credentials!";
}
}
catch (Exception e)
{
retVal.Success = false;
retVal.Message = e.Message;
}
return retVal;
}
{
GetAllResponse retVal = new GetAllResponse();
try
{
if (ValidRequest(request))
{
// Do our SQL stuff here
}
else
{
retVal.Success = false;
retVal.Message = "Invalid Request Credentials!";
}
}
catch (Exception e)
{
retVal.Success = false;
retVal.Message = e.Message;
}
return retVal;
}
public GetAllResponse GetAll(RequestBase request)
{
GetAllResponse retVal = new GetAllResponse();
try
{
if (ValidRequest(request))
{
string sql = "SELECT * FROM TestTable";
DataSet ds = dbUtil.GetDataSet(sql);
if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
retVal = new GetAllResponse(ds.Tables[0].Rows);
else
{
retVal.Message = "There is no data in the table...";
}
}
else
{
retVal.Success = false;
retVal.Message = "Invalid Request Credentials!";
}
}
catch (Exception e)
{
retVal.Success = false;
retVal.Message = e.Message;
}
return retVal;
}
{
GetAllResponse retVal = new GetAllResponse();
try
{
if (ValidRequest(request))
{
string sql = "SELECT * FROM TestTable";
DataSet ds = dbUtil.GetDataSet(sql);
if (ds != null && ds.Tables != null && ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0)
retVal = new GetAllResponse(ds.Tables[0].Rows);
else
{
retVal.Message = "There is no data in the table...";
}
}
else
{
retVal.Success = false;
retVal.Message = "Invalid Request Credentials!";
}
}
catch (Exception e)
{
retVal.Success = false;
retVal.Message = e.Message;
}
return retVal;
}
So, now we are going to put the service up on the interwebz so your applications can access it. First of all, if you did use the debug/remote access server address and port in your web.config file, switch it to the live IP and port now, if you forget, most FTP clients will let you edit files on the server, so it’s no big issue, just makes it a bit easier if you do it now.
Once you are all compiled and ready to go, you need to locate the MySql.Data.dll as this wont be present on the server, it will be in the GAC, so I found mine here “C:\Windows\Microsoft.NET\assembly\GAC_MSIL”, once you have located the assembly, create an ASP.NET Bin folder in the project ad copy the assembly across so it’s ready to go on the server, your solution should now look something like this
Now, I had a few issues setting mine up on my server as I had other web applications using an older version of the MySQL.Data.dll, to get round this I altered the reference to the assembly so it looked like this
<add assembly="MySql.Data, Culture=neutral"/>
So, we have the project all lined up and ready to be served on our server, fire up your FTP client and connect to your host, create a folder to hold the service, I just used the folder name my project is in RCTestWCFService, then just copy it all up. We are still not done, we need to now go over to our control panel and set up the folder as a virtual directory. With my host it’s a pretty simple thing to do, go into the Virtual Directories option off the main menu screen, select the Add New Virtual Directory tab and enter the names you want as the alias and the name you just transferred the service to and click Create virtual directory.
One more step and we will have our service up and running and that’s to refresh your application pool, I think that by default on my host your site is in a shared application pool, but from the dashboard you can switch to an isolated one, then simply hit the refresh application pool button.
So, now (if I have not took it down yet) you should be able to go and see my version of this test service running from my site here http://www.randomchaos.co.uk/RCTestWCFService/RCTestService.svc which should look something like this
And if you click the link at the top you will get to see the WSDL for the service, which will look like this
So that’s that, you have created a simple WCF Web service, now to look at setting up a WP7 Client to access this service.
XNA WP7 Client
So as I hope you by know, I am pretty much 100% XNA on this blog, so I am going to create the WP7 client in pure XNA. So, create your XNA WP7 project as you normally would, we then need to add a service reference, right click on the project and click Add Service Reference
In the Address paste the address of your service and hit the Go button, once the service has been discovered you can change the namespace that will be used in your project, I named mine RCTestService, then click OK
And that’s it, it’s now bound to the service and we can now make the web service calls from the client.
In the Game1 class I create a reference to the service just above the constructor like this
namespace RCTestWP7Client
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
RCTestService.RCTestServiceClient webService;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
GraphicsDeviceManager graphics;
SpriteBatch spriteBatch;
RCTestService.RCTestServiceClient webService;
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
So our Initialize method now looks something like this and we have two new methods
protected override void Initialize()
{
// TODO: Add your initialization logic here
base.Initialize();
webService = new RCTestService.RCTestServiceClient();
webService.UpdateServerCompleted += new EventHandler<RCTestService.UpdateServerCompletedEventArgs>(webService_UpdateServerCompleted);
webService.GetAllCompleted += new EventHandler<RCTestService.GetAllCompletedEventArgs>(webService_GetAllCompleted);
}
void webService_GetAllCompleted(object sender, RCTestService.GetAllCompletedEventArgs e)
{
throw new NotImplementedException();
}
void webService_UpdateServerCompleted(object sender, RCTestService.UpdateServerCompletedEventArgs e)
{
throw new NotImplementedException();
}
{
// TODO: Add your initialization logic here
base.Initialize();
webService = new RCTestService.RCTestServiceClient();
webService.UpdateServerCompleted += new EventHandler<RCTestService.UpdateServerCompletedEventArgs>(webService_UpdateServerCompleted);
webService.GetAllCompleted += new EventHandler<RCTestService.GetAllCompletedEventArgs>(webService_GetAllCompleted);
}
void webService_GetAllCompleted(object sender, RCTestService.GetAllCompletedEventArgs e)
{
throw new NotImplementedException();
}
void webService_UpdateServerCompleted(object sender, RCTestService.UpdateServerCompletedEventArgs e)
{
throw new NotImplementedException();
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (!UpdatedServer)
{
UpdatedServer = true;
RCTestService.UpdateRequest req = new RCTestService.UpdateRequest();
req.UserName = "username";
req.Password = "password";
req.Country = System.Globalization.CultureInfo.CurrentCulture.Name;
webService.UpdateServerAsync(req);
}
base.Update(gameTime);
}
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (!UpdatedServer)
{
UpdatedServer = true;
RCTestService.UpdateRequest req = new RCTestService.UpdateRequest();
req.UserName = "username";
req.Password = "password";
req.Country = System.Globalization.CultureInfo.CurrentCulture.Name;
webService.UpdateServerAsync(req);
}
base.Update(gameTime);
}
public void ShowMessageBox(string title, string message)
{
Guide.BeginShowMessageBox(title, message, new string[] { "OK" }, 0, MessageBoxIcon.Alert, null, null);
}
{
Guide.BeginShowMessageBox(title, message, new string[] { "OK" }, 0, MessageBoxIcon.Alert, null, null);
}
void webService_UpdateServerCompleted(object sender, RCTestService.UpdateServerCompletedEventArgs e)
{
if (e.Result.Success)
ShowMessageBox("All Good", "Server was updated.");
else
ShowMessageBox("Error", e.Result.Message);
}
{
if (e.Result.Success)
ShowMessageBox("All Good", "Server was updated.");
else
ShowMessageBox("Error", e.Result.Message);
}
The variables we now have at the top of Game1 look like this
RCTestService.RCTestServiceClient webService;
List<RCTestService.TableData> getAllResponse = new List<RCTestService.TableData>();
TimeSpan checkTimeSpan = new TimeSpan(0, 1, 0);
TimeSpan lastCheck = DateTime.Now.TimeOfDay;
bool UpdatedServer = false;
List<RCTestService.TableData> getAllResponse = new List<RCTestService.TableData>();
TimeSpan checkTimeSpan = new TimeSpan(0, 1, 0);
TimeSpan lastCheck = DateTime.Now.TimeOfDay;
bool UpdatedServer = false;
void webService_GetAllCompleted(object sender, RCTestService.GetAllCompletedEventArgs e)
{
if (e.Result.Success)
{
getAllResponse = new List<RCTestService.TableData>(e.Result.Data);
}
else
ShowMessageBox("Error", e.Result.Message);
}
{
if (e.Result.Success)
{
getAllResponse = new List<RCTestService.TableData>(e.Result.Data);
}
else
ShowMessageBox("Error", e.Result.Message);
}
protected override void Update(GameTime gameTime)
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (!UpdatedServer)
{
UpdatedServer = true;
RCTestService.UpdateRequest req = new RCTestService.UpdateRequest();
req.UserName = "username";
req.Password = "password";
req.Country = System.Globalization.CultureInfo.CurrentCulture.Name;
webService.UpdateServerAsync(req);
}
else
{
if (DateTime.Now.TimeOfDay - lastCheck > checkTimeSpan)
{
lastCheck = DateTime.Now.TimeOfDay;
RCTestService.RequestBase req = new RCTestService.RequestBase();
req.UserName = "username";
req.Password = "password";
webService.GetAllAsync(req);
}
}
base.Update(gameTime);
}
{
// Allows the game to exit
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
this.Exit();
if (!UpdatedServer)
{
UpdatedServer = true;
RCTestService.UpdateRequest req = new RCTestService.UpdateRequest();
req.UserName = "username";
req.Password = "password";
req.Country = System.Globalization.CultureInfo.CurrentCulture.Name;
webService.UpdateServerAsync(req);
}
else
{
if (DateTime.Now.TimeOfDay - lastCheck > checkTimeSpan)
{
lastCheck = DateTime.Now.TimeOfDay;
RCTestService.RequestBase req = new RCTestService.RequestBase();
req.UserName = "username";
req.Password = "password";
webService.GetAllAsync(req);
}
}
base.Update(gameTime);
}
protected override void Draw(GameTime gameTime)
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/font"), string.Format("Next Check in {0} seconds", (checkTimeSpan - (DateTime.Now.TimeOfDay - lastCheck)).Seconds), Vector2.Zero, Color.Gold);
int cnt = getAllResponse.Count;
for (int l = 0; l < cnt; l++)
spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/font"), string.Format("{0} {1}", getAllResponse[l].Country, getAllResponse[l].Count), new Vector2(0, Content.Load<SpriteFont>("Fonts/font").LineSpacing * (l + 1)), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
{
GraphicsDevice.Clear(Color.Black);
spriteBatch.Begin();
spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/font"), string.Format("Next Check in {0} seconds", (checkTimeSpan - (DateTime.Now.TimeOfDay - lastCheck)).Seconds), Vector2.Zero, Color.Gold);
int cnt = getAllResponse.Count;
for (int l = 0; l < cnt; l++)
spriteBatch.DrawString(Content.Load<SpriteFont>("Fonts/font"), string.Format("{0} {1}", getAllResponse[l].Country, getAllResponse[l].Count), new Vector2(0, Content.Load<SpriteFont>("Fonts/font").LineSpacing * (l + 1)), Color.White);
spriteBatch.End();
base.Draw(gameTime);
}
And once it has gone and got all, looks something like this
Silverlight WP7 Client
So, I am updating this post to include the silver light client code, I am new to Silverlight on the WP7, so please forgive how crude I have been writing this client. It’s pretty much the same steps as the XNA client, we add a reference to the service, just as before, but we set the service up in code in the MainPage constructor like this
public MainPage()
{
InitializeComponent();
webService = new RCTestService.RCTestServiceClient();
webService.UpdateServerCompleted += new EventHandler<RCTestService.UpdateServerCompletedEventArgs>(webService_UpdateServerCompleted);
webService.GetAllCompleted += new EventHandler<RCTestService.GetAllCompletedEventArgs>(webService_GetAllCompleted);
RCTestService.UpdateRequest request = new RCTestService.UpdateRequest();
request.UserName = "username";
request.Password = "password";
request.Country = System.Globalization.CultureInfo.CurrentCulture.Name;
webService.UpdateServerAsync(request);
runThread = true;
timer.Start();
txtCounter.Text = string.Format("Data will be updated every {0} seconds.", checkTimeSpan.Seconds);
}
{
InitializeComponent();
webService = new RCTestService.RCTestServiceClient();
webService.UpdateServerCompleted += new EventHandler<RCTestService.UpdateServerCompletedEventArgs>(webService_UpdateServerCompleted);
webService.GetAllCompleted += new EventHandler<RCTestService.GetAllCompletedEventArgs>(webService_GetAllCompleted);
RCTestService.UpdateRequest request = new RCTestService.UpdateRequest();
request.UserName = "username";
request.Password = "password";
request.Country = System.Globalization.CultureInfo.CurrentCulture.Name;
webService.UpdateServerAsync(request);
runThread = true;
timer.Start();
txtCounter.Text = string.Format("Data will be updated every {0} seconds.", checkTimeSpan.Seconds);
}
void webService_GetAllCompleted(object sender, RCTestService.GetAllCompletedEventArgs e)
{
if (e.Result.Success)
{
getAllResponse = new List<RCTestService.TableData>(e.Result.Data);
RunAsCrossThreadSafeCode(
delegate
{
txtData.Text = string.Empty;
foreach (RCTestService.TableData data in getAllResponse)
{
txtData.Text += string.Format("{0} {1}\n", data.Country, data.Count);
}
});
}
else
MessageBox.Show("Error", e.Result.Message, MessageBoxButton.OK);
}
void webService_UpdateServerCompleted(object sender, RCTestService.UpdateServerCompletedEventArgs e)
{
if (e.Result.Success)
{
MessageBox.Show("All Good", "Server was updated.", MessageBoxButton.OK);
}
else
MessageBox.Show("Error", e.Result.Message, MessageBoxButton.OK);
}
{
if (e.Result.Success)
{
getAllResponse = new List<RCTestService.TableData>(e.Result.Data);
RunAsCrossThreadSafeCode(
delegate
{
txtData.Text = string.Empty;
foreach (RCTestService.TableData data in getAllResponse)
{
txtData.Text += string.Format("{0} {1}\n", data.Country, data.Count);
}
});
}
else
MessageBox.Show("Error", e.Result.Message, MessageBoxButton.OK);
}
void webService_UpdateServerCompleted(object sender, RCTestService.UpdateServerCompletedEventArgs e)
{
if (e.Result.Success)
{
MessageBox.Show("All Good", "Server was updated.", MessageBoxButton.OK);
}
else
MessageBox.Show("Error", e.Result.Message, MessageBoxButton.OK);
}
static void callTimer()
{
while (runThread)
{
if (DateTime.Now.TimeOfDay - lastCheck > checkTimeSpan)
{
lastCheck = DateTime.Now.TimeOfDay;
RCTestService.RequestBase req = new RCTestService.RequestBase();
req.UserName = "username";
req.Password = "password";
webService.GetAllAsync(req);
}
Thread.Sleep(1);
}
}
{
while (runThread)
{
if (DateTime.Now.TimeOfDay - lastCheck > checkTimeSpan)
{
lastCheck = DateTime.Now.TimeOfDay;
RCTestService.RequestBase req = new RCTestService.RequestBase();
req.UserName = "username";
req.Password = "password";
webService.GetAllAsync(req);
}
Thread.Sleep(1);
}
}
/// <summary>
/// Method to run a delegate as cross thread safe code
/// </summary>
/// <param name="code">Code to be ran</param>
protected static void RunAsCrossThreadSafeCode(CrossThreadCode code)
{
using (AutoResetEvent are = new AutoResetEvent(false))
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// Code here
code();
are.Set();
});
are.WaitOne();
}
}
/// Method to run a delegate as cross thread safe code
/// </summary>
/// <param name="code">Code to be ran</param>
protected static void RunAsCrossThreadSafeCode(CrossThreadCode code)
{
using (AutoResetEvent are = new AutoResetEvent(false))
{
System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// Code here
code();
are.Set();
});
are.WaitOne();
}
}
/// <summary>
/// Delegate used to run none cross thread safe code in a cross thread safe manor.
/// </summary>
protected delegate void CrossThreadCode();
/// Delegate used to run none cross thread safe code in a cross thread safe manor.
/// </summary>
protected delegate void CrossThreadCode();
And that’s pretty much it really. I know it seems like a lot to sort out and to take in at first, but once you have written a few services you will love it, I do :) I know I may go around the houses and do stuff the long winded way, so if you read this and have any advice or tips to add then please feel free to comment and let us all know how you stream line the process. Or you know of a great host for ASP.NET, share that too. If you have any issues creating your WCF service then let us know, you never know we might be able to help :P
Hope I have not scared you off of confused you when it comes to creating services for your game, and I hope this post helps you realize the potential you have in your game with web services.
ALL the source is available here [Not yet uploaded]
Thank you SO much for this tutorial.
ReplyDeleteFinally I got a decent metrics collecting service up on my hobby video game! This is worth so much to me.
Thank you so much!!!
Cool, glad you found the post useful :)
Delete