I\'ve written a small hello world test app in Silverlight which i want to host on a Linux/Apache2 server. I want the data to come from MySQL (or some other linux compatible
You can get data from MySQL by using Web Services.
Walkthrough:
Step 1: Create Web Services
Step 2: Add Service Reference to Silverlight
Add a new Silverlight project.
Create a new Web Service. Right click on the web project > Add > New Item
Select "Web Service".
Initial code of a new Web Service.
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
namespace SilverlightApplication1.Web
{
/// <summary>
/// Summary description for WebService1
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class WebService1 : System.Web.Services.WebService
{
[WebMethod]
public string HelloWorld()
{
return "Hello World";
}
}
}
In order for the Web Service able to connect to MySQL, we need to add a reference of MySql.Data.DLL into the web project and add the Using statement at top of the Web Service class:
using MySql.Data.MySqlClient;
HelloWorld() is an initial sample method created by Visual Studio. You may want to delete it as it is not needed. I'm going to create 2 simple method to demonstrate how Web Services are used to communicate between SilverLight and MySQL.
First method: ExecuteScalar()
This method is simple. Get a single object from MySQL.
public string ExecuteScalar(string sql)
{
try
{
string result = "";
using (MySqlConnection conn = new MySqlConnection(constr))
{
using (MySqlCommand cmd = new MySqlCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandText = sql;
result = cmd.ExecuteScalar() + "";
conn.Close();
}
}
return result;
}
catch (Exception ex)
{
return ex.Message;
}
}
Second method: ExecuteNonQuery()
For single SQL execution. Example of SQL type: INSERT, UPDATE, DELETE.
public string ExecuteNonQuery(string sql)
{
try
{
long i = 0;
using (MySqlConnection conn = new MySqlConnection(constr))
{
using (MySqlCommand cmd = new MySqlCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandText = sql;
i = cmd.ExecuteNonQuery();
conn.Close();
}
}
return i + " row(s) affected by the last command, no resultset returned.";
}
catch (Exception ex)
{
return ex.Message;
}
}
This is how the Web Service looks like after adding the two methods above:
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using MySql.Data.MySqlClient;
namespace SilverlightApplication1.Web
{
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class WebService1 : System.Web.Services.WebService
{
string constr = "server=localhost;user=root;pwd=1234;database=test;";
[WebMethod]
public string ExecuteScalar(string sql)
{
try
{
string result = "";
using (MySqlConnection conn = new MySqlConnection(constr))
{
using (MySqlCommand cmd = new MySqlCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandText = sql;
result = cmd.ExecuteScalar() + "";
conn.Close();
}
}
return result;
}
catch (Exception ex)
{
return ex.Message;
}
}
[WebMethod]
public string ExecuteNonQuery(string sql)
{
try
{
long i = 0;
using (MySqlConnection conn = new MySqlConnection(constr))
{
using (MySqlCommand cmd = new MySqlCommand())
{
conn.Open();
cmd.Connection = conn;
cmd.CommandText = sql;
i = cmd.ExecuteNonQuery();
conn.Close();
}
}
return i + " row(s) affected by the last command, no resultset returned.";
}
catch (Exception ex)
{
return ex.Message;
}
}
}
}
You will notice that an attribute of [WebMethod] is added to the methods.
Rebuild the project and let the Web Service be ready for next step.
Web Service Access Permission
Please note that, by default, Web Service only allow those Silverlight that is hosted at the same domain with the Web Service to access. If the Silverlight application is hosted on another website/domain, Web Service will deny the communication. Therefore we have to configure the permission for the Web Service to be accessed by Silverlight which is hosted at different domain.
You have to create two additional files: clientaccesspolicy.xml and crossdomain.xml.
These files has to be put at the root of the domain where the Web Services are hosted.
Example: http://www.mywebsite.com/clientaccesspolicy.xml
and http://www.mywebsite.com/crossdomain.xml
clientaccesspolicy.xml
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="SOAPAction">
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
If you only want to allow the Web Service to be accessed by specific domain (example: www.myanotherwebsite.com), you can add it within . Example:
<?xml version="1.0" encoding="utf-8"?>
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="SOAPAction">
<domain uri="http://www.myanotherwebsite.com"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
crossdomain.xml
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE cross-domain-policy SYSTEM
"http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
<allow-http-request-headers-from domain="*" headers="SOAPAction,Content-Type"/>
</cross-domain-policy>
To understand more about this, please read: Making a Service Available Across Domain Boundaries (MSDN)
Step 2: Add Service Reference to Silverlight
Add a Service Reference to Silverlight.
Type the address of the Web Service and press [Go].
Example of address: http://www.mywebsite.com/MyCoolWebService.asmx
Change the Namespace to your favor, and press [OK].
Visual Studio will analyze the Web Service, do the data binding and create a class.
Before continue coding, let's us see what methods that we can use in the new created class. Right click the new class and select [View in Object Browser].
The class that we are going to use is WebService1SoapClient (in this example). The naming is based on the Service name. If we name our service class as MyCoolWebService, then MyCoolWebServiceSoapClient will be chosen as the name of the class in Silverlight. At the right panel, two methods and two events are highlighted. Those are the methods used to call the Web Services.
Lets create a simple Silverlight application by adding a Textbox and two Buttons.
In this example, user will key in SQL query directly into the Textbox.
Button of [ExecuteScalar] will send the SQL to the Web Service and retrieve data back. (SELECT, SHOW, etc.)
Button of [ExecuteNonQuery] will send the SQL to the Web Service for execution only. (INSERT, UPDATE, DELETE, etc.)
This is the initial code behind of MainPage.xaml:
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;
namespace SilverlightApplication1
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
}
private void btExecuteScalar_Click(object sender, RoutedEventArgs e)
{
}
private void btExecuteNonQuery_Click(object sender, RoutedEventArgs e)
{
}
}
}
Now, these are what we are going to do here:
public partial class MainPage : UserControl
{
ServiceReference1.WebService1SoapClient myService;
public MainPage()
{
InitializeComponent();
myService = new ServiceReference1.WebService1SoapClient();
myService.ExecuteScalarCompleted += myService_ExecuteScalarCompleted;
myService.ExecuteNonQueryCompleted += myService_ExecuteNonQueryCompleted;
}
void myService_ExecuteNonQueryCompleted(object sender,
ServiceReference1.ExecuteNonQueryCompletedEventArgs e)
{
MessageBox.Show(e.Result);
}
void myService_ExecuteScalarCompleted(object sender,
ServiceReference1.ExecuteScalarCompletedEventArgs e)
{
MessageBox.Show(e.Result);
}
private void btExecuteScalar_Click(object sender, RoutedEventArgs e)
{
myService.ExecuteScalarAsync(textBox1.Text);
}
private void btExecuteNonQuery_Click(object sender, RoutedEventArgs e)
{
myService.ExecuteNonQueryAsync(textBox1.Text);
}
}
Press [F5], run and test the Silverlight application.
Together with your creativity, I believe you can do something more than this for now Smile | :)
If you have done any changes to the Web Service, maybe you added new Service (new web methods), you have to update the Service Reference at Silverlight to re-bind the Services. You might want to update the Web Service address, if you uploaded the files to a different web hosting.
Happy coding.
Read More:
Silverlight does not have any capability to directly access database servers. What you can do is to expose your database operations through web services (ASMX or WCF, even non-.NET!) and use Silverlight to access those services.
The easiest way to do what you want (having read through your edits now :)) will be to expose services that can be consumed. The pattern that Microsoft is REALLY pushing right now is to expose WCF services, but the truth is that your Silverlight client can use WCF to consume a lot of different types of services.
What may be easiest for you to do right now would be to use a .NET service on a web server or maybe a PHP REST service, and then point your Silverlight app at that service. By doing so, you're protecting your database not only from people snooping through it, but more importantly, you're restricting what people can do to your database. If your data is supposed to be read-only, and your service's contract only allows reading operations, you're set. Alternatively, your service may negotiate sessions with credentials, again, set up through WCF.
WCF can be a client-only, server-only, or client-server connector platform. What you choose will affect the code you write, but it's all going to be independent of your database. Your code can be structured such that it's a one-to-one mapping to your database table, or it can be far more abstract (you can set up classes that represent full logical views if you choose).
While the "official" answer is to use WCF to push a service to Silverlight, I kind of figure that anyone using MySQL would probably not be using a complete ASP.NET solution. My solution was to build a PHP webservice (like Rob suggested) to interact with the MySQL database and have the Silverlight access it in a RESTful manner.
Here is beginning of a three part tutorial for using Silverlight to access a MySQL database through a PHP web service:
PHP, MySQL and Silverlight: The Complete Tutorial
I just got this working; ASP.NET4 site with Silverlight4 content on Linux Ubuntu 10 / Apache2 server. Content is developed using Visual Studio 2010. VS2008 should work fine too.
Server:
Visual Studio:
Setting up the site with MySQL access:
Here is a guide I found helpful: Step By Step Guide to WCF RIA enabled SL4 application with Entity Framework
Testing:
Let's get data from MySQL into Silverlight. Assuming there is a table named 'persons' with column name 'name', we can bind a list box to show the names of the persons.
First add a Silverlight page, let's say 'Home'. In Home.xaml add:
<ListBox x:Name="TestList" Width="100" />
In Home.xaml.cs file add:
public partial class Home : Page
{
public Home()
{
InitializeComponent();
Loaded += Home_Loaded;
}
void Home_Loaded(object sender, RoutedEventArgs e)
{
var context = new FooDomainContext();
var query = context.Load(context.GetPersonsQuery());
TestList.ItemsSource = query.Entities;
TestList.DisplayMemberPath = "name";
}
}
Here we assume you named your domain service 'FooDomain', and this would generate the 'FooDomainContext' class used.
Hopefully, if all is set up properly, you will now see a list of person names when running your Silverlight project.
Edit: ASP.NET is not optional, but required for the WCF RIA web service used in my example.
Having DB connections directly to the server from the client side is usually a bad idea. I don't know how easy it is to decompile a Silverlight app, but I would guess it's possible in some way. Then you're basically giving away your DB credentials to your users.